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