Quantcast
Channel: CodeSection,代码区,Python开发技术文章_教程 - CodeSec
Viewing all articles
Browse latest Browse all 9596

Using Borg in Parallel and Serial with a Python Wrapper

$
0
0

Simulation and optimization are frequently used to solve complex water resources and environmental systems problems. By itself, a simulation model begs the question “what to simulate?” Similarly, by itself, an optimization model begs the question “is the solution really best?” For this reason, simulation and optimization models are frequently coupled. In this blog post, I provide a sample of code that demonstrates how I have coupled a pure python simulation model with the multi-objective evolutionary optimization algorithm Borg. I will show how you can access Borg’s serial and/or parallelized (master-slave) implementations through a Python wrapper (borg.py).

Please see this previous blogpost for some background about Borg, and how to obtain it. My instructions below assume you have access to the Borg files.

In the setup I will describe below, Borg parameterizes and iteratively refines solutions (e.g., reservoir operating policies) to a problem, optimizing them in response to their simulated performance with respect to multiple objectives.

You will need the following Borg files (see link above for how to download these):

Serial (i.e., borg.c , libborg.so , etc.) and/or master-slave (i.e., borgms.c , libborgms.so , etc.) implementations of Borg, depending uponyour ability to parallelize. Python wrapper for Borg ( borg.py ), which will allow you to to access Borg easily in Python.

You will need to create the following files yourself (I provide sample code below for these files):

example_sim_opt.py ―A python module that should contain two main functions: A simulation caller, which takes decision variables and returns multi-objective performance. This function is called “Simulation_Caller” in the example_sim_opt.py code below. An optimization function, which calls the Borg MOEA through its python wrapper borg.py . This borg.py wrapper provides extensive docstring documentation regarding required arguments, returned values, etc., so I do suggest reading through the wrapper if you have questions (e.g., about the python data types of arguments and returns).

Note that the file and function names above are just example names. You can name the above files whatever you want. Just be sure to modify the code I provide below to reflect the new names.

A sample of code for example_sim_opt.py is as follows:

import numpy as np import pysedsim # This is your simulation model import platform # helps identify directory locations on different types of OS def Simulation_Caller(vars): ''' Purpose: Borg calls this function to run the simulation model and return multi-objective performance. Note: You could also just put your simulation/function evaluation code here. Args: vars: A list of decision variable values from Borg Returns: performance: policy's simulated objective values. A list of objective values, one value each of the objectives. ''' borg_vars = vars # Decision variable values from Borg # Reformat decision variable values as necessary (.e.g., cast borg output parameters as array for use in simulation) op_policy_params = np.asarray(borg_vars) # Call/run simulation model, return multi-objective performance: performance = pysedsim.PySedSim(decision_vars = op_policy_params) return performance def Optimization(): ''' Purpose: Call this method from command line to initiate simulation-optimization experiment Returns: --pareto approximate set file (.set) for each random seed --Borg runtime file (.runtime) for each random seed ''' import borg as bg # Import borg wrapper parallel = 1 # 1= master-slave (parallel), 0=serial # The following are just examples of relevant MOEA specifications. Select your own values. nSeeds = 25 # Number of random seeds (Borg MOEA) num_dec_vars = 10 # Number of decision variables n_objs = 6 # Number of objectives n_constrs = 0 # Number of constraints num_func_evals = 30000 # Number of total simulations to run per random seed. Each simulation may be a monte carlo. runtime_freq = 1000 # Interval at which to print runtime details for each random seed decision_var_range = [[0, 1], [4, 6], [-1,4], [1,2], [0,1], [0,1], [0,1], [0,1], [0,1], [0,1]] epsilon_list = [50000, 1000, 0.025, 10, 13, 4] # Borg epsilon values for each objective # Where to save seed and runtime files main_output_file_dir = 'E:\output_directory' # Specify location of output files for different seeds os_fold = Op_Sys_Folder_Operator() # Folder operator for operating system output_location = main_output_file_dir + os_fold + 'sets' # If using master-slave, start MPI. Only do once. if parallel == 1: bg.Configuration.startMPI() # start parallelization with MPI # Loop through seeds, calling borg.solve (serial) or borg.solveMPI (parallel) each time for j in range(nSeeds): # Instantiate borg class, then set bounds, epsilon values, and file output locations borg = bg.Borg(num_dec_vars, n_objs, n_constrs, Simulation_Caller) borg.setBounds(*decision_var_range) # Set decision variable bounds borg.setEpsilons(*epsilon_list) # Set epsilon values # Runtime file path for each seed: runtime_filename = main_output_file_dir + os_fold + 'runtime_file_seed_' + str(j+1) + '.runtime' if parallel == 1: # Run parallel Borg result = borg.solveMPI(maxEvaluations='num_func_evals', runtime=runtime_filename, frequency=runtime_freq) if parallel == 0: # Run serial Borg result = borg.solve({"maxEvaluations": num_func_evals, "runtimeformat": 'borg', "frequency": runtime_freq, "runtimefile": runtime_filename}) if result: # This particular seed is now finished being run in parallel. The result will only be returned from # one node in case running Master-Slave Borg. result.display() # Create/write objective values and decision variable values to files in folder "sets", 1 file per seed. f = open(output_location + os_fold + 'Borg_DPS_PySedSim' + str(j+1) + '.set', 'w') f.write('#Borg Optimization Results\n') f.write('#First ' + str(num_dec_vars) + ' are the decision variables, ' + 'last ' + str(n_objs) + ' are the ' + 'objective values\n') for solution in result: line = '' for i in range(len(solution.getVariables())): line = line + (str(solution.getVariables()[i])) + ' ' for i in range(len(solution.getObjectives())): line = line + (str(solution.getObjectives()[i])) + ' ' f.write(line[0:-1]+'\n') f.write("#") f.close() # Create/write only objective values to files in folder "sets", 1 file per seed. Purpose is so that # the file can be processed in MOEAFramework, where performance metrics may be evaluated across seeds. f2 = open(output_location + os_fold + 'Borg_DPS_PySedSim_no_vars' + str(j+1) + '.set', 'w') for solution in result: line = '' for i in range(len(solution.getObjectives())): line = line + (str(solution.getObjectives()[i])) + ' ' f2.write(line[0:-1]+'\n') f2.write("#") f2.close() print("Seed %s complete") %j

Viewing all articles
Browse latest Browse all 9596

Trending Articles