From 4872a0c10721ffa9c0f76e0e9264749649b2b664 Mon Sep 17 00:00:00 2001
From: "Mads M. Pedersen" <mmpe@dtu.dk>
Date: Fri, 1 Jun 2018 10:27:57 +0200
Subject: [PATCH] Added FusedWakeNOJWakeModel + test

---
 tests/test_fusedwake_models/test_gcl.py    | 52 ++++++++----------
 tests/test_fusedwake_models/test_noj.py    | 32 +++++++++++
 tests/test_try_me.py                       |  8 ++-
 topfarm/cost_models/fused_wake_wrappers.py | 63 +++++++++++++++-------
 4 files changed, 105 insertions(+), 50 deletions(-)
 create mode 100644 tests/test_fusedwake_models/test_noj.py

diff --git a/tests/test_fusedwake_models/test_gcl.py b/tests/test_fusedwake_models/test_gcl.py
index c393bd18..0a8bf30a 100644
--- a/tests/test_fusedwake_models/test_gcl.py
+++ b/tests/test_fusedwake_models/test_gcl.py
@@ -1,43 +1,37 @@
-import os
-import unittest
-
 import numpy as np
 from topfarm.cost_models.fused_wake_wrappers import FusedWakeGCLWakeModel
 from topfarm.cost_models.utils.aep_calculator import AEPCalculator
 from topfarm.cost_models.utils.wind_resource import WindResource
 from tests.test_files import tfp
 from topfarm._topfarm import TopFarm
+import pytest
 
 
-class TestFusedWakeModels(unittest.TestCase):  # unittest version
+@pytest.fixture()
+def aep_calc():
+    # f, A, k = read_lib(fuga_path + 'LUT/Farms/Horns Rev 1\hornsrev_north_only_pm45.lib')
+    f = [1.0, 0.0, 0.0, 0.0]
+    A = [9.176929, 9.782334, 9.531809, 9.909545]
+    k = [2.392578, 2.447266, 2.412109, 2.591797]
+    wr = WindResource(f, A, k, ti=np.zeros_like(f) + .1)
+    wm = FusedWakeGCLWakeModel(tfp + "wind_farms/3tb.yml")
+    return AEPCalculator(wr, wm)
 
-    def test_GCL(self):
-        # f, A, k = read_lib(fuga_path + 'LUT/Farms/Horns Rev 1\hornsrev_north_only_pm45.lib')
-        f = [1.0, 0.0, 0.0, 0.0]
-        A = [9.176929, 9.782334, 9.531809, 9.909545]
-        k = [2.392578, 2.447266, 2.412109, 2.591797]
 
-        wr = WindResource(f, A, k, ti=np.zeros_like(f) + .1)
-        wm = FusedWakeGCLWakeModel(tfp + "wind_farms/3tb.yml")
-        aep_calc = AEPCalculator(wr, wm)
-        init_pos = wm.windFarm.pos.T
-        self.assertEqual(aep_calc(init_pos), 19.85973533524627)
-        self.assertEqual(aep_calc(np.array([[-500, 0, 500], [0, 0, 0]]).T), 22.31788007605505)
+def test_input_shape_must_be_equal():
+    wm = FusedWakeGCLWakeModel(tfp + "wind_farms/3tb.yml")
+    with pytest.raises(AssertionError, message="Shape of no_wake_wdir, no_wake_wsp and no_wake_ti must equal"):
+        wm(wm.windFarm.pos.T, no_wake_wdir=[[270]], no_wake_wsp=[[8, 9]], no_wake_ti=0.1)
 
-    def test_GCL_Topfarm(self):
-        # f, A, k = read_lib(fuga_path + 'LUT/Farms/Horns Rev 1\hornsrev_north_only_pm45.lib')
-        f = [1.0, 0.0, 0.0, 0.0]
-        A = [9.176929, 9.782334, 9.531809, 9.909545]
-        k = [2.392578, 2.447266, 2.412109, 2.591797]
 
-        wr = WindResource(f, A, k, ti=np.zeros_like(f) + .1)
-        wm = FusedWakeGCLWakeModel(tfp + "wind_farms/3tb.yml")
-        aep_calc = AEPCalculator(wr, wm)
-        init_pos = wm.windFarm.pos.T
-        tf = TopFarm(init_pos, aep_calc.get_TopFarm_cost_component(), 160, init_pos, boundary_type='square')
-        tf.evaluate()
-        self.assertEqual(tf.get_cost(), -19.85973533524627)
+def test_GCL(aep_calc):
+    init_pos = aep_calc.wake_model.windFarm.pos.T
+    assert aep_calc(init_pos) == 19.85973533524627  # tb aligned north-south -> wake
+    assert aep_calc(np.array([[-500, 0, 500], [0, 0, 0]]).T) == 22.31788007605505  # tb aligned West-East -> no wake
 
 
-if __name__ == "__main__":
-    unittest.main()
+def test_GCL_Topfarm(aep_calc):
+    init_pos = aep_calc.wake_model.windFarm.pos.T
+    tf = TopFarm(init_pos, aep_calc.get_TopFarm_cost_component(), 160, init_pos, boundary_type='square')
+    tf.evaluate()
+    assert tf.get_cost() == -19.85973533524627
diff --git a/tests/test_fusedwake_models/test_noj.py b/tests/test_fusedwake_models/test_noj.py
new file mode 100644
index 00000000..703a26a6
--- /dev/null
+++ b/tests/test_fusedwake_models/test_noj.py
@@ -0,0 +1,32 @@
+import pytest
+
+import numpy as np
+from tests.test_files import tfp
+from topfarm._topfarm import TopFarm
+from topfarm.cost_models.fused_wake_wrappers import FusedWakeNOJWakeModel
+from topfarm.cost_models.utils.aep_calculator import AEPCalculator
+from topfarm.cost_models.utils.wind_resource import WindResource
+
+
+@pytest.fixture()
+def aep_calc():
+    # f, A, k = read_lib(fuga_path + 'LUT/Farms/Horns Rev 1\hornsrev_north_only_pm45.lib')
+    f = [1.0, 0.0, 0.0, 0.0]
+    A = [9.176929, 9.782334, 9.531809, 9.909545]
+    k = [2.392578, 2.447266, 2.412109, 2.591797]
+    wr = WindResource(f, A, k, ti=np.zeros_like(f) + .1)
+    wm = FusedWakeNOJWakeModel(tfp + "wind_farms/3tb.yml")
+    return AEPCalculator(wr, wm)
+
+
+def test_GCL(aep_calc):
+    init_pos = aep_calc.wake_model.windFarm.pos.T
+    assert aep_calc(init_pos) == 18.90684500124578
+    assert aep_calc(np.array([[-500, 0, 500], [0, 0, 0]]).T) == 22.31788007605505
+
+
+def test_GCL_Topfarm(aep_calc):
+    init_pos = aep_calc.wake_model.windFarm.pos.T
+    tf = TopFarm(init_pos, aep_calc.get_TopFarm_cost_component(), 160, init_pos, boundary_type='square')
+    tf.evaluate()
+    assert tf.get_cost() == -18.90684500124578
diff --git a/tests/test_try_me.py b/tests/test_try_me.py
index 5ede5239..a98000f1 100644
--- a/tests/test_try_me.py
+++ b/tests/test_try_me.py
@@ -5,6 +5,7 @@ import warnings
 import mock
 import pytest
 import topfarm
+import matplotlib.pyplot as plt
 
 
 def get_try_me_modules():
@@ -21,9 +22,14 @@ def get_try_me_modules():
 
 @pytest.mark.parametrize("module", get_try_me_modules())
 def test_try_me(module):
-    # check that all try_me module examples run without errors 
+    # check that all try_me module examples run without errors
     if os.name == 'posix' and "DISPLAY" not in os.environ:
         pytest.xfail("No display")
     print("Checking %s.try_me" % module.__name__)
+
+    def no_show(*args, **kwargs):
+        pass
+    plt.show = no_show  # disable plt show that requires the use to close the plot
+
     with mock.patch.object(module, "__name__", "__main__"):
         getattr(module, 'try_me')()
diff --git a/topfarm/cost_models/fused_wake_wrappers.py b/topfarm/cost_models/fused_wake_wrappers.py
index cfa170aa..18dd10d0 100644
--- a/topfarm/cost_models/fused_wake_wrappers.py
+++ b/topfarm/cost_models/fused_wake_wrappers.py
@@ -7,11 +7,12 @@ import pytest
 from fusedwake.WindFarm import WindFarm
 from fusedwake.gcl.interface import GCL
 import numpy as np
+from fusedwake.noj.interface import NOJ
 
 
-class FusedWakeGCLWakeModel(object):
+class FusedWakeModel(object):
 
-    def __init__(self, yml):
+    def __init__(self, yml, version=None, **kwargs):
         """Description
 
         Parameters
@@ -20,37 +21,59 @@ class FusedWakeGCLWakeModel(object):
             A WindIO `yml` file containing the description of the farm
         """
         self.windFarm = WindFarm(yml=yml)
+        if version:
+            self.version = version
         try:
-            self.gcl = GCL(WF=self.windFarm, version='fort_gcl')
+            self.wake_model = self.wake_model_cls(WF=self.windFarm, version=self.version, **kwargs)
         except ValueError as e:
             pytest.xfail(str(e))
 
     def __call__(self, turbine_positions, no_wake_wdir, no_wake_wsp, no_wake_ti):
-        self.gcl.update_position(turbine_positions.T)
-
-        WD, WS, TI = [np.mean(np.atleast_3d(v), 0) for v in [no_wake_wdir, no_wake_wsp, no_wake_ti]]
-        self.gcl(WS=WS.flatten(), WD=WD.flatten(), TI=TI.flatten())
-        p = self.gcl.p_wt
+        self.wake_model.update_position(turbine_positions.T)
+        WD, WS, TI = (np.atleast_2d(v) for v in [no_wake_wdir, no_wake_wsp, no_wake_ti])
+        assert WD.shape == WS.shape == TI.shape, "Shape of no_wake_wdir, no_wake_wsp and no_wake_ti must equal: %s != %s != %s" % (WD.shape, WS.shape, TI.shape)
+        if len(WD.shape) == 3:
+            WD, WS, TI = [np.mean(v, 0) for v in [WD, WS, TI]]
+        self.run_wake_model(WS, WD, TI)
+        p = self.wake_model.p_wt
         p = p.reshape(WD.shape + (self.windFarm.nWT,))
         return p.sum(2)  # sum over all turbines
 
+    def run_wake_model(self, WS, WD, TI):
+        self.wake_model(WS=WS.flatten(), WD=WD.flatten(), TI=TI.flatten())
+
+
+class FusedWakeGCLWakeModel(FusedWakeModel):
+    wake_model_cls = GCL
+    version = 'fort_gcl'
+
+
+class FusedWakeNOJWakeModel(FusedWakeModel):
+    wake_model_cls = NOJ
+    version = 'fort_noj'
+
 
 def try_me():
     if __name__ == '__main__':
         from fusedwake import fusedwake
         import os
-
+        import matplotlib.pyplot as plt
         hornsrev_yml = os.path.dirname(fusedwake.__file__) + "/../examples/hornsrev.yml"
-        wm = FusedWakeGCLWakeModel(hornsrev_yml)
-        tb_pos = wm.windFarm.pos
-
-        print(wm(tb_pos.T, no_wake_wdir=270, no_wake_wsp=8, no_wake_ti=0.1))
-
-        WS_cases = np.arange(4, 12)
-        WD_cases = np.arange(0, 360, 10)
-        WS_ms, WD_ms = np.meshgrid(WS_cases, WD_cases)
-        p = wm(tb_pos.T, WD_ms, WS_ms, np.zeros_like(WS_ms) + .1)
-        print(p)
-
+        noj, gcl = wake_models = [FusedWakeNOJWakeModel(hornsrev_yml, K=.1), FusedWakeGCLWakeModel(hornsrev_yml)]
+        tb_pos = noj.windFarm.pos
+        print(noj(tb_pos.T, no_wake_wdir=270, no_wake_wsp=8, no_wake_ti=0.1))
+    
+        for wm, c in zip(wake_models,'rk'):
+            WS_cases = np.arange(11, 12)
+            WD_cases = np.arange(0, 360, 1)
+            WD_ms, WS_ms = np.meshgrid(WD_cases, WS_cases)
+            p = wm(tb_pos.T, WD_ms, WS_ms, np.zeros_like(WS_ms) + .1)
+            plt.xlabel("Wdir")
+            plt.ylabel("Power")
+            plt.plot(p.T, color=c, label=wm.wake_model_cls.__name__)
+            plt.legend()
+            print(p.sum())
+        plt.show()
+        
 
 try_me()
-- 
GitLab