From f6b1b22b0d797ae424ce645e1c9561c08f6c1d2e Mon Sep 17 00:00:00 2001 From: "Mads M. Pedersen" <mmpe@dtu.dk> Date: Thu, 14 Jun 2018 10:22:29 +0200 Subject: [PATCH] implemented easy_drivers.py --- tests/topfarm/__init__.py | 0 tests/topfarm/test_drivers.py | 73 ++++++++++++++++++++++++ tests/{ => topfarm}/test_topfarm.py | 0 topfarm/_topfarm.py | 17 +++--- topfarm/cost_models/dummy.py | 3 - topfarm/easy_drivers.py | 88 +++++++++++++++++++++++++++++ 6 files changed, 169 insertions(+), 12 deletions(-) create mode 100644 tests/topfarm/__init__.py create mode 100644 tests/topfarm/test_drivers.py rename tests/{ => topfarm}/test_topfarm.py (100%) create mode 100644 topfarm/easy_drivers.py diff --git a/tests/topfarm/__init__.py b/tests/topfarm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/topfarm/test_drivers.py b/tests/topfarm/test_drivers.py new file mode 100644 index 00000000..718db758 --- /dev/null +++ b/tests/topfarm/test_drivers.py @@ -0,0 +1,73 @@ +''' +Created on 17. maj 2018 + +@author: mmpe +''' +from topfarm import TopFarm + +import numpy as np +import pytest +from topfarm.cost_models.dummy import DummyCost, DummyCostPlotComp +from topfarm.plotting import NoPlot +from topfarm.easy_drivers import EasyScipyOptimizeDriver, EasySimpleGADriver + + +initial = [[6, 0], [6, -8], [1, 1]] # initial turbine layouts +optimal = np.array([[2.5, -3], [6, -7], [4.5, -3]]) # desired turbine layouts +boundary = [(0, 0), (6, 0), (6, -10), (0, -10)] # turbine boundaries +desired = [[3, -3], [7, -7], [4, -3]] # desired turbine layouts + + +@pytest.fixture +def topfarm_generator(): + def _topfarm_obj(driver): + plot_comp = DummyCostPlotComp(desired) + #plot_comp = NoPlot() + return TopFarm(initial, DummyCost(desired), 2, plot_comp=plot_comp, boundary=boundary, driver=driver) + return _topfarm_obj + + + + +# # CONMIN-specific Settings +# self.driver.itmax = 30 +# self.driver.fdch = 0.00001 +# self.driver.fdchm = 0.000001 +# self.driver.ctlmin = 0.01 +# self.driver.delfun = 0.001 +# +# # NEWSUMT-specific Settings +# #self.driver.itmax = 10 +# +# # COBYLA-specific Settings +# #self.driver.rhobeg = 1.0 +# #self.driver.rhoend = 1.0e-4 +# #self.driver.maxfun = 1000 +# +# # SLSQP-specific Settings +# #self.driver.accuracy = 1.0e-6 +# #self.driver.maxiter = 50 +# +# # Genetic-specific Settings +# #self.driver.population_size = 90 +# #self.driver.crossover_rate = 0.9 +# #self.driver.mutation_rate = 0.02 +# #self.selection_method = 'rank' + + +@pytest.mark.parametrize('driver,tol',[(EasyScipyOptimizeDriver(), 1e-4), + (EasyScipyOptimizeDriver(tol=1e-3), 1e-2), + (EasyScipyOptimizeDriver(maxiter=13), 1e-1), + (EasyScipyOptimizeDriver(optimizer='COBYLA', tol=1e-3), 1e-2), + #(EasyPyOptSparseSLSQP(),??), + (EasySimpleGADriver(), 1e-4)][-1:]) +def test_optimizers(driver, tol, topfarm_generator): + tf = topfarm_generator(driver) + tf.optimize() + tb_pos = tf.turbine_positions + #tf.plot_comp.show() + + assert sum((tb_pos[2] - tb_pos[0])**2) > 2**2 - tol # check min spacing + assert tb_pos[1][0]< 6 + tol # check within border + np.testing.assert_array_almost_equal(tb_pos, optimal, -int(np.log10(tol))) + #print (tb_pos - optimal) diff --git a/tests/test_topfarm.py b/tests/topfarm/test_topfarm.py similarity index 100% rename from tests/test_topfarm.py rename to tests/topfarm/test_topfarm.py diff --git a/topfarm/_topfarm.py b/topfarm/_topfarm.py index 572c9efa..c145ea4a 100644 --- a/topfarm/_topfarm.py +++ b/topfarm/_topfarm.py @@ -19,7 +19,7 @@ class TopFarm(object): """ def __init__(self, turbines, cost_comp, min_spacing, boundary, boundary_type='convex_hull', plot_comp=None, - driver_options={'optimizer': 'SLSQP'}): + driver=ScipyOptimizeDriver()): self.initial_positions = turbines = np.array(turbines) @@ -32,19 +32,18 @@ class TopFarm(object): indeps = prob.model.add_subsystem('indeps', IndepVarComp(), promotes=['*']) min_x, min_y = self.boundary_comp.vertices.min(0) mean_x, mean_y = self.boundary_comp.vertices.mean(0) - if driver_options['optimizer'] == 'SLSQP': + design_var_kwargs = {} + + if 'optimizer' in driver.options and driver.options['optimizer'] == 'SLSQP': min_x, min_y, mean_x, mean_y = 0, 0, 1, 1 # scaling disturbs SLSQP + # Default +/- sys.float_info.max does not work for SLSQP + design_var_kwargs = {'lower': np.nan, 'upper': np.nan} indeps.add_output('turbineX', turbines[:, 0], units='m', ref0=min_x, ref=mean_x) indeps.add_output('turbineY', turbines[:, 1], units='m', ref0=min_y, ref=mean_y) indeps.add_output('boundary', self.boundary_comp.vertices, units='m') prob.model.add_subsystem('cost_comp', cost_comp, promotes=['*']) - prob.driver = ScipyOptimizeDriver() - - prob.driver.options.update(driver_options) - design_var_kwargs = {} - if driver_options['optimizer'] == 'SLSQP': - # Default +/- sys.float_info.max does not work for SLSQP - design_var_kwargs = {'lower': np.nan, 'upper': np.nan} + prob.driver = driver + prob.model.add_design_var('turbineX', **design_var_kwargs) prob.model.add_design_var('turbineY', **design_var_kwargs) prob.model.add_objective('cost') diff --git a/topfarm/cost_models/dummy.py b/topfarm/cost_models/dummy.py index 777b77f8..77a99f00 100644 --- a/topfarm/cost_models/dummy.py +++ b/topfarm/cost_models/dummy.py @@ -19,9 +19,6 @@ class DummyCost(ExplicitComponent): self.optimal = np.array(optimal_positions) self.N = self.optimal.shape[0] - def cost(self, x, y): - """Evaluate cost function""" - def setup(self): self.add_input('turbineX', val=np.zeros(self.N), units='m') self.add_input('turbineY', val=np.zeros(self.N), units='m') diff --git a/topfarm/easy_drivers.py b/topfarm/easy_drivers.py new file mode 100644 index 00000000..3f63aa71 --- /dev/null +++ b/topfarm/easy_drivers.py @@ -0,0 +1,88 @@ +from openmdao.drivers.scipy_optimizer import ScipyOptimizeDriver +#from openmdao.drivers.pyoptsparse_driver import pyOptSparseDriver +from openmdao.drivers.genetic_algorithm_driver import SimpleGADriver + + +class EasyScipyOptimizeDriver(ScipyOptimizeDriver): + + def __init__(self, optimizer='SLSQP', maxiter=200, tol=1e-6, disp=True): + """ + Parameters + ---------- + optimizer : {'Nelder-Mead', 'Powell', 'CG', 'BFGS', 'Newton-CG', 'L-BFGS-B', + 'TNC', 'COBYLA', 'SLSQP'} + Inequality constraints are supported by COBYLA and SLSQP, + but equality constraints are only supported by SLSQP. None of the other + optimizers support constraints. + maxiter : int + Maximum number of iterations. + tol : float + Tolerance for termination. For detailed control, use solver-specific options. + disp : bool + Set to False to prevent printing of Scipy convergence messages + """ + ScipyOptimizeDriver.__init__(self) + self.options.update({'optimizer': optimizer, 'maxiter': maxiter, 'tol': tol, 'disp': disp}) + + +# class EasyPyOptSparseSLSQP(pyOptSparseDriver): +# def __init__(self, maxit=200, acc=1e-6): +# pyOptSparseDriver.__init__(self) +# raise NotImplementedError + + +class EasySimpleGADriver(SimpleGADriver): + def __init__(self, elitism=True, max_gen=100): + """Simple Genetic Algorithm Driver with argument + + Parameters + ---------- + bits : dict + Number of bits of resolution. Default is an empty dict, where every unspecified variable is assumed to be integer, and the number of bits is calculated automatically. If you have a continuous var, you should set a bits value as a key in this dictionary. + NotImplemented + debug_print : list + List of what type of Driver variables to print at each iteration. Valid items in list are ‘desvars’, ‘ln_cons’, ‘nl_cons’, ‘objs’, ‘totals’ + NotImplemented + elitism : bool + If True, replace worst performing point with best from previous generation each iteration. + max_gen : int + Number of generations before termination. + pop_size : + Number of points in the GA. Set to 0 and it will be computed as four times the number of bits. + NotImplemented + procs_per_model : int + Number of processors to give each model under MPI. + NotImplemented + run_parallel : bool + Set to True to execute the points in a generation in parallel. + NotImplemented + """ + SimpleGADriver.__init__(self) + self.options.update({'elitism': elitism, 'max_gen': max_gen}) + +# +# class COBYLADriverWrapper(CONMINdriver): +# # CONMIN-specific Settings +# self.driver.itmax = 30 +# self.driver.fdch = 0.00001 +# self.driver.fdchm = 0.000001 +# self.driver.ctlmin = 0.01 +# self.driver.delfun = 0.001 +# +# # NEWSUMT-specific Settings +# #self.driver.itmax = 10 +# +# # COBYLA-specific Settings +# #self.driver.rhobeg = 1.0 +# #self.driver.rhoend = 1.0e-4 +# #self.driver.maxfun = 1000 +# +# # SLSQP-specific Settings +# #self.driver.accuracy = 1.0e-6 +# #self.driver.maxiter = 50 +# +# # Genetic-specific Settings +# #self.driver.population_size = 90 +# #self.driver.crossover_rate = 0.9 +# #self.driver.mutation_rate = 0.02 +# #self.selection_method = 'rank' -- GitLab