From 7b1217f6735c072b54083e30ac33398588653fa2 Mon Sep 17 00:00:00 2001 From: mikf <mikf@dtu.dk> Date: Tue, 26 Jun 2018 14:32:59 +0200 Subject: [PATCH] animations now possible --- topfarm/_topfarm.py | 48 +++++++++++++++++++++++++++------------------ topfarm/plotting.py | 35 +++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/topfarm/_topfarm.py b/topfarm/_topfarm.py index c210f2fb..6c1e8ecb 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,38 @@ 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 +71,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 +89,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 +135,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 +155,12 @@ 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() - + tf.post_process() try_me() 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): -- GitLab