diff --git a/tests/test_with_dummy.py b/tests/test_with_dummy.py index 398852100c68baa56a2cfbfbb37a2fbb49741ccc..e0026c3f78797ccf3ee80584e7b421596bbd0214 100644 --- a/tests/test_with_dummy.py +++ b/tests/test_with_dummy.py @@ -1,69 +1,45 @@ """Tests for TOPFARM """ import warnings - import numpy as np from topfarm.topfarm import TopFarm +from topfarm.cost_models.dummy import DummyCost +import unittest -from topfarm.cost_models.dummy import DummyCost_v2 - - -def test_optimize_4tb(): - """Optimize 4-turbine layout and check final positions - - The farm boundaries and min spacing are chosen such that the desired - turbine positions are not within the boundaries or constraints. - """ - - # test options - dec_prec = 4 # decimal precision for comparison - - # given - boundary = [(0, 0), (6, 0), (6, -10), (0, -10)] # turbine boundaries - initial = [[6, 0], [6, -8], [1, 1], [-1, -8]] # initial turbine layouts - desired = [[3, -3], [7, -7], [4, -3], [3, -7]] # desired turbine layouts - optimal = np.array([[2.5, -3], [6, -7], - [4.5, -3], [3, -7]]) # optimal turbine layout - min_spacing = 2 # min distance between turbines - # when - tf = TopFarm(initial, DummyCost_v2(desired), min_spacing, - boundary=boundary) - tf.evaluate() - with warnings.catch_warnings(): # suppress OpenMDAO/SLSQP warnings - warnings.simplefilter('ignore') - tf.optimize() - tb_pos = tf.turbine_positions +class Test(unittest.TestCase): # unittest version - # # then - np.testing.assert_array_almost_equal(tb_pos, optimal, dec_prec) + def test_optimize_4tb(self): + """Optimize 4-turbine layout and check final positions + The farm boundaries and min spacing are chosen such that the desired + turbine positions are not within the boundaries or constraints. + """ -# class Test(unittest.TestCase): # unittest version + # test options + dec_prec = 4 # decimal precision for comparison - # def test_topfarm_with_dummy(self): - # from topfarm.cost_models.dummy import DummyCost, DummyCostPlotComp + # given + boundary = [(0, 0), (6, 0), (6, -10), (0, -10)] # turbine boundaries + initial = [[6, 0], [6, -8], [1, 1], [-1, -8]] # initial turbine layouts + desired = [[3, -3], [7, -7], [4, -3], [3, -7]] # desired turbine layouts + optimal = np.array([[2.5, -3], [6, -7], [4.5, -3], [3, -7]]) # optimal turbine layout + min_spacing = 2 # min distance between turbines - # eps = 1e-6 - # optimal = [(3, -3), (7, -7), (4, -3), (3, -7)] - # initial = [[6, 0], [6, -8], [1, 1], [-1, -8]] - # boundary = [(0, 0), (6, 0), (6, -10), (0, -10)] - # plot = True - # plot_comp = None - # if plot: - # plot_comp = DummyCostPlotComp(optimal) - # tf = TopFarm(initial, DummyCost(optimal), 2, boundary=boundary, plot_comp=plot_comp) - # tf.evaluate() - # tf.optimize() + # when + tf = TopFarm(initial, DummyCost(desired), min_spacing, + boundary=boundary) + with warnings.catch_warnings(): # suppress OpenMDAO/SLSQP warnings + warnings.simplefilter('ignore') + tf.optimize() + tb_pos = tf.turbine_positions - # tb_pos = tf.turbine_positions - # self.assertGreater(sum((tb_pos[2] - tb_pos[0])**2), 2**2 - eps) - # np.testing.assert_array_almost_equal(tb_pos[3], optimal[3], 3) - # self.assertLess(tb_pos[1][0], 6 + eps) - # if plot: - # plot_comp.show() + # then + tol = 1e-6 + self.assertGreater(sum((tb_pos[2] - tb_pos[0])**2), 2**2 - tol) # check min spacing + self.assertLess(tb_pos[1][0], 6 + tol) # check within border + np.testing.assert_array_almost_equal(tb_pos, optimal, dec_prec) -# if __name__ == "__main__": - # #import sys;sys.argv = ['', 'Test.test_topfarm'] - # unittest.main() +if __name__ == "__main__": + unittest.main() diff --git a/topfarm/cost_models/dummy.py b/topfarm/cost_models/dummy.py index 0088698abc658fd2e4d2ca80896950101db22676..21dc7e45b2c09188f7f3b22779d929962f36503c 100644 --- a/topfarm/cost_models/dummy.py +++ b/topfarm/cost_models/dummy.py @@ -7,55 +7,6 @@ from topfarm.topfarm import TopFarm class DummyCost(ExplicitComponent): - """Evaluates the equation f(x,y) = (x-optimal_x)^2 + (y+optimal_y)^2 - 3. - """ - - def __init__(self, optimal_positions): - ExplicitComponent.__init__(self) - self.optimal = np.array(optimal_positions) - self.N = self.optimal.shape[0] - self.history = [] - - def cost(self, x, y, optimal=None): - if optimal is not None: - opt_x, opt_y = optimal - else: - opt_x, opt_y = np.array(self.optimal).T - #return (x - opt_x)**2 + (x - opt_x) * (y - opt_y) + (y - opt_y)**2 - 3.0 - return (x - opt_x)**2 + (y - opt_y)**2 - 3.0 - - 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') - - self.add_output('cost', val=0.0) - - # Finite difference all partials. - self.declare_partials('cost', '*') - #self.declare_partials('*', '*', method='fd') - - def compute(self, inputs, outputs): - """ - f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3 - - Optimal solution (minimum): x = 6.6667; y = -7.3333 - """ - x = inputs['turbineX'] - y = inputs['turbineY'] - - #print(x, y, sum(self.cost(x, y))) - outputs['cost'] = np.sum(self.cost(x, y)) - - def compute_partials(self, inputs, J): - x = inputs['turbineX'] - y = inputs['turbineY'] - #J['aep', 'turbineX'] = -(2 * x - 2 * np.array(self.optimal)[:, 0] + y - np.array(self.optimal)[:, 1]) - #J['aep', 'turbineY'] = -(2 * y - 2 * np.array(self.optimal)[:, 1] + x - np.array(self.optimal)[:, 0]) - J['cost', 'turbineX'] = (2 * x - 2 * np.array(self.optimal)[:, 0]) - J['cost', 'turbineY'] = (2 * y - 2 * np.array(self.optimal)[:, 1]) - - -class DummyCost_v2(ExplicitComponent): """Sum of squared error between current positions and optimal positions Evaluates the equation @@ -67,31 +18,24 @@ class DummyCost_v2(ExplicitComponent): ExplicitComponent.__init__(self) self.optimal = np.array(optimal_positions) self.N = self.optimal.shape[0] - self.history = [] def cost(self, x, y): """Evaluate cost function""" - opt_x, opt_y = self.optimal.T - return np.sum((x - opt_x)**2 + (y - opt_y)**2) - + 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') - self.add_output('cost', val=0.0) - - # Finite difference all partials. self.declare_partials('cost', '*') - # self.declare_partials('*', '*', method='fd') - + def compute(self, inputs, outputs): """ f(x,y) = SUM(x_i - optx_i)^2 + SUM(y_i + opty_i)^2 """ x = inputs['turbineX'] y = inputs['turbineY'] - - outputs['cost'] = self.cost(x, y) + opt_x, opt_y = self.optimal.T + outputs['cost'] = np.sum((x - opt_x)**2 + (y - opt_y)**2) def compute_partials(self, inputs, J): x = inputs['turbineX'] @@ -99,18 +43,17 @@ class DummyCost_v2(ExplicitComponent): J['cost', 'turbineX'] = (2 * x - 2 * np.array(self.optimal)[:, 0]) J['cost', 'turbineY'] = (2 * y - 2 * np.array(self.optimal)[:, 1]) + class DummyCostPlotComp(PlotComp): def __init__(self, optimal, memory=10): super().__init__(memory) self.optimal = optimal - + def init_plot(self, boundary): PlotComp.init_plot(self, boundary) for c, (optx, opty) in zip(self.colors, self.optimal): plt.plot(optx, opty, 'ko', ms=10) - plt.plot(optx, opty, 'o',color=c, ms=8) - - + plt.plot(optx, opty, 'o', color=c, ms=8) if __name__ == '__main__': @@ -127,4 +70,4 @@ if __name__ == '__main__': tf = TopFarm(turbines, DummyCost(optimal), minSpacing * rotorDiameter, boundary=boundary, plot_comp=plot_comp) # tf.check() tf.optimize() - plot_comp.show() \ No newline at end of file + plot_comp.show() diff --git a/topfarm/cost_models/utils/aep_calculator.py b/topfarm/cost_models/utils/aep_calculator.py index c956d2fcee71e31c9542c0a865fb1c1334d1756a..fbbc28cf4c261b4b3a379d30669060a8dd8eb695 100644 --- a/topfarm/cost_models/utils/aep_calculator.py +++ b/topfarm/cost_models/utils/aep_calculator.py @@ -16,8 +16,8 @@ class AEPCalculator(object): def __init__(self, wind_resource, wake_model, wdir=np.arange(360), wsp=np.arange(3, 25)): """ - wind_resource: f(turbine_positions, wdir, wsp) -> WS[nWT,nWdir,nWsp], TI[nWT,nWdir,nWsp), Weight[nWdir,nWsp] - wake_model: f(turbine_positions, WS[nWT,nWdir,nWsp], TI[nWT,nWdir,nWsp) -> power[nWdir,nWsp] + wind_resource: f(turbine_positions, wdir, wsp) -> WD[nWT,nWdir,nWsp], WS[nWT,nWdir,nWsp], TI[nWT,nWdir,nWsp), Weight[nWdir,nWsp] + wake_model: f(turbine_positions, WD[nWT,nWdir,nWsp], WS[nWT,nWdir,nWsp], TI[nWT,nWdir,nWsp) -> power[nWdir,nWsp] (W) """ self.wind_resource = wind_resource self.wake_model = wake_model