From 153c273fe781e7f245fe8dc26fa75e2491f5b6f3 Mon Sep 17 00:00:00 2001 From: mikf <mikf@dtu.dk> Date: Tue, 26 Jun 2018 10:16:42 +0200 Subject: [PATCH] renamed recording to utils new random initial positions feature that respects the boundaries and tries to respect the min spacing animations now possible added test-file to optimization recording testing and tests to the utility module misc. updates. try make utils tests pass animations now possible added test-file to optimization recording testing and tests to the utility module more tests --- topfarm/_topfarm.py | 49 ++++++------ .../spacing_component.py | 2 +- topfarm/plotting.py | 35 +++++++-- .../recordings/cases_20180621_111710.sql | Bin 0 -> 65536 bytes topfarm/tests/topfarm/test_utils.py | 70 ++++++++++++++++++ topfarm/utils.py | 33 +++++---- 6 files changed, 143 insertions(+), 46 deletions(-) create mode 100644 topfarm/tests/test_files/recordings/cases_20180621_111710.sql create mode 100644 topfarm/tests/topfarm/test_utils.py diff --git a/topfarm/_topfarm.py b/topfarm/_topfarm.py index c210f2fb..e0ba0d9a 100644 --- a/topfarm/_topfarm.py +++ b/topfarm/_topfarm.py @@ -1,3 +1,8 @@ +from topfarm.constraint_components.boundary_component import BoundaryComp,\ + PolygonBoundaryComp +from topfarm.constraint_components.spacing_component import SpacingComp +from topfarm.plotting import PlotComp +from topfarm.utils import pos_from_case, latest_id import os import time import numpy as np @@ -5,41 +10,37 @@ import warnings with warnings.catch_warnings(): warnings.simplefilter('ignore', FutureWarning) from openmdao.api import Problem, ScipyOptimizeDriver, IndepVarComp, \ - SqliteRecorder -from topfarm.constraint_components.boundary_component import BoundaryComp,\ - PolygonBoundaryComp -from topfarm.constraint_components.spacing_component import SpacingComp -from topfarm.plotting import PlotComp -from topfarm.utils import pos_from_case, latest_id - + SqliteRecorder class TopFarm(object): - """Optimize wind farm layout in terms of + """Optimize wind farm layout in terms of - Position of turbines [- Type of turbines: Not implemented yet] [- Height of turbines: Not implemented yet] [- Number of turbines: Not implemented yet] """ - def __init__(self, turbines, cost_comp, min_spacing, boundary, boundary_type='convex_hull', plot_comp=None, - driver=ScipyOptimizeDriver(), record = False, case_recorder_dir = os.getcwd(), - rerun_case_id = None): + def __init__(self, turbines, cost_comp, min_spacing, boundary, + boundary_type='convex_hull', plot_comp=None, + driver=ScipyOptimizeDriver(), record=False, + case_recorder_dir=os.getcwd(), rerun_case_id=None): if rerun_case_id is None: self.initial_positions = turbines = np.array(turbines) elif rerun_case_id is 'latest': rerun_case_id = latest_id(case_recorder_dir) - self.initial_positions = turbines = pos_from_case(rerun_case_id) + self.initial_positions = turbines = pos_from_case(rerun_case_id) print('*Initial positions loaded from file: {}\n'.format( rerun_case_id)) else: - self.initial_positions = turbines = pos_from_case(rerun_case_id) + self.initial_positions = turbines = pos_from_case(rerun_case_id) n_wt = turbines.shape[0] if boundary_type == 'polygon': self.boundary_comp = PolygonBoundaryComp(boundary, n_wt) else: self.boundary_comp = BoundaryComp(boundary, n_wt, boundary_type) self.problem = prob = Problem() - indeps = prob.model.add_subsystem('indeps', IndepVarComp(), promotes=['*']) + 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) design_var_kwargs = {} @@ -69,8 +70,10 @@ class TopFarm(object): prob.model.add_design_var('turbineY', **design_var_kwargs) prob.model.add_objective('cost') - prob.model.add_subsystem('spacing_comp', SpacingComp(nTurbines=n_wt), promotes=['*']) - prob.model.add_subsystem('bound_comp', self.boundary_comp, promotes=['*']) + prob.model.add_subsystem('spacing_comp', SpacingComp(nTurbines=n_wt), + promotes=['*']) + prob.model.add_subsystem('bound_comp', self.boundary_comp, + promotes=['*']) if plot_comp == "default": plot_comp = PlotComp() if plot_comp: @@ -85,8 +88,6 @@ class TopFarm(object): prob.setup(check=True, mode='fwd') - - def check(self, all=False, tol=1e-3): """Check gradient computations""" comp_name_lst = [comp.pathname for comp in self.problem.model.system_iter() @@ -133,6 +134,14 @@ class TopFarm(object): return np.array([self.problem['turbineX'], self.problem['turbineY']]).T + def post_process(self, anim_time=10, verbose=True): + if self.plot_comp.animate: + self.plot_comp.run_animate(anim_time, verbose) + for file in os.listdir(self.plot_comp.temp): + if file.startswith('plot_') and file.endswith('.png'): + os.remove(os.path.join(self.plot_comp.temp,file)) + + def try_me(): if __name__ == '__main__': from topfarm.cost_models.dummy import DummyCostPlotComp, DummyCost @@ -145,12 +154,10 @@ def try_me(): turbines = np.array(optimal) + np.random.randint(-random_offset, random_offset, (n_wt, 2)) plot_comp = DummyCostPlotComp(optimal) + plot_comp.animate = True boundary = [(0, 0), (6, 0), (6, -10), (0, -10)] tf = TopFarm(turbines, DummyCost(optimal), minSpacing * rotorDiameter, boundary=boundary, plot_comp=plot_comp) # tf.check() tf.optimize() - # plot_comp.show() - - try_me() diff --git a/topfarm/constraint_components/spacing_component.py b/topfarm/constraint_components/spacing_component.py index 7d056981..96c96452 100644 --- a/topfarm/constraint_components/spacing_component.py +++ b/topfarm/constraint_components/spacing_component.py @@ -85,4 +85,4 @@ class SpacingComp(ExplicitComponent): dSdy[k, i] = -2 * (turbineY[j] - turbineY[i]) # increment turbine pair counter k += 1 - return dSdx, dSdy + return dSdx, dSdy \ No newline at end of file diff --git a/topfarm/plotting.py b/topfarm/plotting.py index 5715eca6..10944afe 100644 --- a/topfarm/plotting.py +++ b/topfarm/plotting.py @@ -1,8 +1,6 @@ -import time - import matplotlib from openmdao.core.explicitcomponent import ExplicitComponent - +import os import matplotlib.pyplot as plt import numpy as np @@ -23,13 +21,15 @@ def mypause(interval): class PlotComp(ExplicitComponent): colors = ['b', 'r', 'm', 'c', 'g', 'y', 'orange', 'indigo', 'grey'] * 100 - def __init__(self, memory=10, delay=0.001, plot_initial=True): + def __init__(self, memory=10, delay=0.001, plot_initial=True, + animate=False): ExplicitComponent.__init__(self) self.memory = memory self.delay = delay self.plot_initial = plot_initial self.history = [] self.counter = 0 + self.animate = animate def show(self): plt.show() @@ -59,20 +59,29 @@ class PlotComp(ExplicitComponent): cost = inputs['cost'][0] if not hasattr(self, "initial"): self.initial = np.array([x, y]).T, cost - self.history = [(x.copy(), y.copy())] + self.history[:self.memory] boundary = inputs['boundary'] self.init_plot(boundary) - plt.title("%f (%.2f%%)"%(cost, (self.initial[1]-cost)/self.initial[1]*100)) + plt.title("%f (%.2f%%)" % (cost, + (self.initial[1]-cost)/self.initial[1]*100)) history_arr = np.array(self.history) for i, c, x_, y_ in zip(range(len(x)), self.colors, x, y): if self.plot_initial: - plt.plot([self.initial[0][i, 0], x_], [self.initial[0][i, 1], y_], '-', color=c, lw=1) - plt.plot(history_arr[:, 0, i], history_arr[:, 1, i], '.--', color=c, lw=1) + plt.plot([self.initial[0][i, 0], x_], + [self.initial[0][i, 1], y_], '-', color=c, lw=1) + plt.plot(history_arr[:, 0, i], history_arr[:, 1, i], '.--', + color=c, lw=1) plt.plot(x_, y_, 'o', color=c, ms=5) plt.plot(x_, y_, 'x' + 'k', ms=4) + self.temp = '../__animations__' + if not os.path.exists(self.temp): + os.makedirs(self.temp) + if self.animate: + path = os.path.join(self.temp, + 'plot_{:05d}.png'.format(self.counter)) + plt.savefig(path) if self.counter == 0: plt.pause(.01) @@ -80,6 +89,16 @@ class PlotComp(ExplicitComponent): self.counter += 1 + def run_animate(self, anim_time=10, verbose=False): + N = anim_time/self.counter + string = 'ffmpeg -f image2 -r 1/' + string += '{} -i {}//plot_%05d.png'.format(N, self.temp) + string += ' -vcodec mpeg4 -y {}//animation.mp4'.format(self.temp) + if verbose: + print('\nCreating animation:') + print(string) + os.system(string) + class NoPlot(PlotComp): def __init__(self, *args, **kwargs): diff --git a/topfarm/tests/test_files/recordings/cases_20180621_111710.sql b/topfarm/tests/test_files/recordings/cases_20180621_111710.sql new file mode 100644 index 0000000000000000000000000000000000000000..333ed874528c1456d084669030001f40fc79731a GIT binary patch literal 65536 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 EfA^zzHvj+t literal 0 HcmV?d00001 diff --git a/topfarm/tests/topfarm/test_utils.py b/topfarm/tests/topfarm/test_utils.py new file mode 100644 index 00000000..c4c8400a --- /dev/null +++ b/topfarm/tests/topfarm/test_utils.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +from topfarm import TopFarm +import numpy as np +from topfarm.cost_models.cost_model_wrappers import CostModelComponent +import pytest +import os + +from topfarm.utils import pos_from_case, latest_id, _random_positions + +thisdir = os.path.dirname(os.path.abspath(__file__)) +turbines = np.array([[ 2.4999377 , -2.99987763], + [ 6. , -6.99997496], + [ 4.49993771, -2.99985273], + [ 3.00004123, -6.9999519 ]]) +x = np.array([-0.5463264 , 0.4158521 , 1.50479727, 3.04121982, 0.82494571, + 1.48072571, 0.03939927, 2.27593243, -0.18551361, 0.24885285, + 1.12706339, 2.25472924, 0.04329133, 0.292686 , 5.18916103, + 1.76294032, 6.96910295, 4.80383887, 5.93002915, 6.07458626]) + +y = np.array([-4.28630451, -1.03701919, -6.11562032, 0.60293213, -6.83330699, + -1.9655984 , -7.06706521, -3.56006813, 0.70979837, -2.17497837, + 0.94819493, -1.94630408, -6.75376048, -6.97213247, -7.11506022, + -6.99383667, 0.63581096, -4.57807581, -2.76544057, -8.85507948]) + +boundary = [(0, 0), (6, 1), (7, -11), (-1, -10)] +n_wt, n_iter, step_size, min_space, pad, plot, verbose = \ + (20, 1000, 0.1, 2.1, 1.01, False, False) +turbines2_ref = np.array([[-0.53056298, -5.34414632], + [ 1.72713409, -1.7339491 ], + [ 3.90444365, -5.82606831], + [ 4.49089193, 0.74539327], + [ 1.26552562, -6.75507526], + [ 1.45466343, -4.37313716], + [-0.99102804, -9.94909137], + [ 3.8725124 , -3.68277265], + [-0.02498702, -0.28473405], + [-0.25686194, -2.60098671], + [ 2.30453881, 0.38010616], + [ 3.97302933, -1.39592567], + [-0.74326151, -7.47172573], + [ 1.4151898 , -9.31374061], + [ 5.65712132, -7.44164592], + [ 3.56099506, -8.48762334], + [ 6.12959435, -0.59355499], + [ 6.27224495, -5.30888086], + [ 6.34616645, -3.15591179], + [ 6.42858562, -9.90795045]]) + +def testpos_from_case(): + crf = "../test_files/recordings/cases_20180621_111710.sql" + path = os.path.join(thisdir, crf) + np.testing.assert_allclose(turbines, pos_from_case(path)) + + +def testlatest_id(): + crd = "../test_files/recordings" + path = os.path.join(thisdir, crd) + ref_path = os.path.join(path,'cases_20180621_111710.sql') + assert latest_id(path) == ref_path + +def test_random_positions(): + turbines2 = _random_positions(x, y, boundary, n_wt, n_iter, step_size, + min_space, pad, plot, verbose) + np.testing.assert_allclose(turbines2, turbines2_ref) + +if __name__ == '__main__': +# testpos_from_case() +# testlatest_id() +# test_random_positions() + pass \ No newline at end of file diff --git a/topfarm/utils.py b/topfarm/utils.py index df16d39d..18894baf 100644 --- a/topfarm/utils.py +++ b/topfarm/utils.py @@ -46,16 +46,16 @@ def latest_id(case_recorder_dir): return latest -def random_positions(boundary, n_wt, n_iter, step_size, min_space, - pad = 1.1, plot=False, verbose=True): +def random_positions(boundary, n_wt, n_iter, step_size, min_space, + pad=1.1, plot=False, verbose=True): ''' Input: boundary: list of tuples, e.g.: [(0, 0), (6, 1), (7, -11), (-1, -10)] n_wt: number of wind turbines n_iter: number of iterations allowed to try and satisfy the minimum spacing constraint - step_size: the multiplier on the spacing gradient that the turbines - are moved in each step + step_size: the multiplier on the spacing gradient that the turbines + are moved in each step min_space: the minimum spacing between turbines pad: the multiplier on the boundary gradient plot: plot the generated random layout @@ -113,8 +113,7 @@ def _random(b): def _contain(n_wt, turbineX, turbineY, boundary_comp, pad): for i in range(0, n_wt): - dng = boundary_comp.calc_distance_and_gradients(turbineX, - turbineY) + dng = boundary_comp.calc_distance_and_gradients(turbineX, turbineY) dist = dng[0][i] if dist < 0: dx = dng[1][i] @@ -125,23 +124,25 @@ def _contain(n_wt, turbineX, turbineY, boundary_comp, pad): if __name__ == '__main__': -# this_dir = os.path.dirname(os.path.abspath(__file__)) -# crf = r"C:\Sandbox\Git\TopFarm2\topfarm\cases_20180621_111710.sql" -# case_recorder_filename = crf -# turbines = pos_from_case(case_recorder_filename) -# print(turbines) -# -# case_recorder_dir = r'C:\Sandbox\Git\TopFarm2\topfarm' -# latest_id = latest_id(case_recorder_dir) -# print(latest_id) + this_dir = os.getcwd() + crf = r"tests\test_files\recordings\cases_20180621_111710.sql" + case_recorder_filename = crf + path = os.path.join(this_dir, crf) + turbines = pos_from_case(path) + print(turbines) + + case_recorder_dir = r'tests\test_files\recordings' + latest_id = latest_id(case_recorder_dir) + print(latest_id) boundary = [(0, 0), (6, 1), (7, -11), (-1, -10)] n_wt = 20 n_iter = 1000 step_size = 0.1 min_space = 2.1 + pad = 1.01 plot = True verbose = True turbines = random_positions(boundary, n_wt, n_iter, step_size, min_space, - plot, verbose) + pad, plot, verbose) print(turbines) -- GitLab