From b233dd6db069de33509acc33397318479beb4dd1 Mon Sep 17 00:00:00 2001
From: "Mads M. Pedersen" <mmpe@dtu.dk>
Date: Fri, 28 Jul 2017 08:53:47 +0200
Subject: [PATCH] added constraint_file

---
 wetb/wind/turbulence/constraint_file.py       | 149 ++++++++++++++++++
 .../turbulence/tests/test_constraint_file.py  | 114 ++++++++++++++
 .../tests/test_files/constraints_test.con     |   3 +
 3 files changed, 266 insertions(+)
 create mode 100644 wetb/wind/turbulence/constraint_file.py
 create mode 100644 wetb/wind/turbulence/tests/test_constraint_file.py
 create mode 100644 wetb/wind/turbulence/tests/test_files/constraints_test.con

diff --git a/wetb/wind/turbulence/constraint_file.py b/wetb/wind/turbulence/constraint_file.py
new file mode 100644
index 0000000..0d20024
--- /dev/null
+++ b/wetb/wind/turbulence/constraint_file.py
@@ -0,0 +1,149 @@
+import numpy as np
+import os
+from wetb.hawc2.htc_file import HTCFile
+class ConstraintFile(object):
+    
+    def __init__(self, center_gl_xyz, box_transport_speed, no_grid_points=(4096, 32, 32), box_size=(6000, 100, 100)):
+        """Generate list of constraints for turbulence constraint simulator
+
+        Parameters
+        ----------
+        center_gl_xyz : (float, float, float)
+            Box front plane center position in global coordinates
+        box_transport_speed : float or int
+            Reference wind speed [m/s] (box transportation speed)
+        no_grid_points : [int, int, int]
+            Number of grid points in x,y,z direction of the turbulence box
+        box_size : [float, float, float]
+            Dimension(length) of box in x,y,z direction [m]
+        """
+        self.center_gl_xyz = center_gl_xyz
+        self.box_transport_speed = box_transport_speed
+        self.no_grid_points = no_grid_points
+        self.box_size = box_size
+        self.dxyz = [d / (n - 1) for d, n in zip(self.box_size, self.no_grid_points)]
+
+        self.constraints = {'u':[], 'v':[], 'w':[]}
+        
+    def load(self, filename):
+        """Load constraint from existing constraint file (usable for plotting constraints via time_series()"""
+        with open(filename) as fid:
+            lines = fid.readlines()
+        for l in lines:
+            values = l.split(";")
+            mx,my,mz= map(int, values[:3])
+            comp = values[3]#{"100":'u','010':'v','001':'w'}["".join(values[3:6])]
+            self.constraints[comp].append((mx,my,mz,float(values[-1])))
+            
+
+    def add_constraints(self, glpos, tuvw, subtract_mean=True, fail_outside_box=True, nearest=True):
+        """Add constraints to constraint file
+        
+        parameters
+        ----------
+        glpos : (float or array_like, float or array_like, float or array_like)
+            global position(s), (x,y,z) of measurement point point(s)\n
+            x: horizontal left seen in direction of mean wind, y: direction of mean wind, z: vertical down\n
+        tuvw: array_like (shape: no_obs x (1+no_components))
+            time and u[, v[, w]] components of wind at measurement point\n
+            v and w components are optional\n
+        subtract_mean : boolean, optional
+            if True, default, the mean values are subtracted from u,v,w
+        fail_outside_box : boolean, optional
+            if True, default, an error is raised if any positions are outside the box\n
+            if False, mann coordinates modulo N is used
+        nearest : boolean, optional
+            if True, the wsp at the position closest to the mann grid point are applied\n
+            if False, the average of all the wsp, that map to the mann grid point are applied 
+        """
+        nx, ny, nz = self.no_grid_points
+        dx, dy, dz = self.dxyz
+        center_x, center_y, center_z = self.center_gl_xyz
+
+        time, u, v, w = (list(tuvw.T) + [None, None])[:4]
+        x, y, z = glpos
+        mxs = np.round((time * self.box_transport_speed + (center_y - y)) / dx).astype(np.int)
+        if not np.array(y).shape==mxs.shape:
+            y = np.zeros_like(mxs)+y
+        if not np.array(x).shape==mxs.shape:
+            x = np.zeros_like(mxs)+x 
+        if not np.array(z).shape==mxs.shape:
+            z = np.zeros_like(mxs)+z
+        x_err = y-(-(mxs*dx-time*self.box_transport_speed-center_y))
+        mys = np.round(((ny - 1) / 2. + (-x+center_x) / dy)).astype(np.int)
+        mzs = np.round(((nz - 1) / 2. + (center_z - z) / dz)).astype(np.int)
+
+        y_err = x-(-((mys-(ny-1)/2)*dy-center_x))
+        z_err = z-(-(mzs-(nz-1)/2)*dz+center_z)
+        pos_err = np.sqrt(x_err**2+y_err**2+z_err**2)
+        if fail_outside_box:
+            for ms, n in zip([mxs,mys,mzs],self.no_grid_points):
+                if ms.min() + 1 < 1:
+                    i = np.argmin(ms)
+                    raise ValueError("At time, t=%s, global position (%s,%s,%s) maps to grid point (%d,%d,%d) whichs is outside turbulence box, range (1..%d,1..%d,1..%d)" % (time[i], x[i], y[i], z[i], mxs[i] + 1, mys[i] + 1, mzs[i] + 1, nx , ny , nz))
+                if ms.max() + 1 > n:
+                    i = np.argmax(ms)
+                    raise ValueError("At time, t=%s, global position (%s,%s,%s) maps to grid point (%d,%d,%d) whichs is outside turbulence box, range (1..%d,1..%d,1..%d)" % (time[i], x[i], y[i], z[i], mxs[i] + 1, mys[i] + 1, mzs[i] + 1, nx , ny , nz))
+        else:
+            mxs%=nx
+            mys%=ny
+            mzs%=nz
+        mann_pos = ["%06d%02d%02d"%(mx,my,mz) for mx,my,mz in zip(mxs,mys,mzs)]
+        i = 0
+        N = len(mann_pos)
+        uvw_lst = [uvw for uvw in [u,v,w] if uvw is not None]
+        if subtract_mean:
+            uvw_lst = [uvw - uvw.mean() for uvw in uvw_lst]
+        while i<N:
+            for j in range(i+1,N+1):
+                if j==N or mann_pos[i]!=mann_pos[j]:
+                    break
+            for comp, wsp in zip(['u', 'v', 'w'], uvw_lst):
+                if nearest:
+                    value = wsp[i:j][np.argmin(pos_err[i:j])]
+                else: #mean
+                    value = wsp[i:j].mean()
+                self.constraints[comp].append((mxs[i] + 1, mys[i] + 1, mzs[i] + 1, value))
+            i=j
+                    
+
+    def __str__(self):
+        return "\n".join(["%d;%d;%d;%s;%.10f" % (mx, my, mz, comp, value) for comp in ['u', 'v', 'w']
+                          for mx, my, mz, value in self.constraints[comp]])
+
+    def save(self, path, name, folder="./constraints/"):
+        path = os.path.join(path, folder)
+        if not os.path.isdir(path):
+            os.makedirs(path, exist_ok=True)
+        with open(os.path.join(path, "%s.con" % name), 'w') as fid:
+            fid.write(str(self))
+            
+    def time_series(self, y_position=0):
+        time = (np.arange(self.no_grid_points[0])*float(self.dxyz[0]) + y_position)/ self.box_transport_speed
+        u,v,w = [(np.zeros_like(time)+ np.nan)]*3
+        for uvw, constr in zip([u,v,w], [np.array(self.constraints[uvw]) for uvw in 'uvw']):
+            if constr.shape[0]>0:
+                uvw[constr[:,0].astype(np.int)-1] =constr[:,3] 
+        return time, np.array([u,v,w]).T
+    
+
+    def simulation_cmd(self, ae23, L, Gamma, seed, name, folder="./constraints/"):
+        assert isinstance(seed, int) and seed > 0, "seed must be a positive integer"
+        cmd = "./csimu2.exe %d %d %d %.3f %.3f %.3f  " % (self.no_grid_points + self.box_size)
+        cmd += "%.6f %.2f %.2f %d " % (ae23, L, Gamma, seed)
+        cmd += "./turb/%s_s%s %s/%s.con" % (name, seed, folder, name)
+        return cmd
+    
+    def hawc2_mann_section(self, name, seed):
+        htc = HTCFile()
+        mann = htc.wind.add_section("mann")
+        for uvw in 'uvw':
+            setattr(mann, 'filename_%s'%uvw, "./turb/%s_s%04d%s.bin" % ( name, int(seed),uvw))
+        for uvw, l,n in zip('uvw', self.box_size, self.no_grid_points):
+            setattr(mann, 'box_dim_%s'%uvw, [n,l/n])
+        mann.dont_scale = 1
+        return mann
+        
+        
+
+
diff --git a/wetb/wind/turbulence/tests/test_constraint_file.py b/wetb/wind/turbulence/tests/test_constraint_file.py
new file mode 100644
index 0000000..40233f6
--- /dev/null
+++ b/wetb/wind/turbulence/tests/test_constraint_file.py
@@ -0,0 +1,114 @@
+'''
+Created on 02/10/2015
+
+@author: MMPE
+'''
+import unittest
+
+import numpy as np
+from wetb.wind.turbulence.constraint_file import ConstraintFile
+from wetb.utils.test_files import get_test_file
+class TestConstraintFile(unittest.TestCase):
+
+
+    def testConstraintFile(self):
+        time = [0, 1, 2]
+        u = [5, 7, 9]
+        v = [1.5, 1, .5]
+        w = [3, 1, 5]
+        tu = np.array([time, u]).T
+        tuvw = np.array([time, u, v, w]).T
+        glpos = (0, 0, -85)
+        constraint_file = ConstraintFile(center_gl_xyz=(-5, 0, -90), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.add_constraints(glpos, tu)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][1], (6, 4, 4, 0))
+        constraint_file = ConstraintFile(center_gl_xyz=(-5, 0, -90), box_transport_speed=5, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.add_constraints(glpos, tuvw)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][2], (6, 4, 4, 2))
+        np.testing.assert_array_equal(constraint_file.constraints['v'][2], (6, 4, 4, -.5))
+        np.testing.assert_array_equal(constraint_file.constraints['w'][2], (6, 4, 4, 2))
+        constraint_file = ConstraintFile(center_gl_xyz=(-5, 0, -90), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.add_constraints((-10, -4, -95), tu)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][1], (8, 5, 5, 0))
+        constraint_file = ConstraintFile(center_gl_xyz=(-5, 4, -90), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.add_constraints((-10, 0, -95), tu)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][1], (8, 5, 5, 0))
+        #constraint_file.save("./test_files", "constraints_test",'')
+
+    def testConstraintFile_Mxyz(self):
+        time = [0]
+        u = [5]
+        tu = np.array([time, u]).T
+
+        glpos = (0, 0, -85)
+        constraint_file = ConstraintFile(center_gl_xyz=(0, 0, 0), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.add_constraints([0,0,0], tu, subtract_mean=False)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][-1], (1, 5, 5, 5))
+        constraint_file.add_constraints([5,0,0], tu, subtract_mean=False)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][-1], (1, 4, 5, 5))
+        constraint_file.add_constraints([0,0,5], tu, subtract_mean=False)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][-1], (1, 5, 4, 5))
+        constraint_file.add_constraints([0,-10,0], tu, subtract_mean=False)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][-1], (6, 5, 5, 5))
+        
+    def testConstraintFile_center_gl_xyz(self):
+        time = [0]
+        u = [5]
+        tu = np.array([time, u]).T
+
+        constraint_file = ConstraintFile(center_gl_xyz=(0, 0, 0), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.add_constraints([0,0,0], tu, subtract_mean=False)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][-1], (1, 5, 5, 5))
+        
+        constraint_file = ConstraintFile(center_gl_xyz=(0, 0, -5), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.add_constraints([0,0,0], tu, subtract_mean=False)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][-1], (1, 5, 4, 5))
+        
+        constraint_file = ConstraintFile(center_gl_xyz=(-5, 0, 0), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.add_constraints([0,0,0], tu, subtract_mean=False)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][-1], (1, 4, 5, 5))
+        
+        constraint_file = ConstraintFile(center_gl_xyz=(0, 10, 0), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.add_constraints([0,0,0], tu, subtract_mean=False)
+        np.testing.assert_array_equal(constraint_file.constraints['u'][-1], (6, 5, 5, 5))
+        
+
+    def test_outputbox_errors(self):
+        time = [0, 1, 2]
+        u = [5, 7, 9]
+        v = [1.5, 1, .5]
+        w = [3, 1, 5]
+        tu = np.array([time, u]).T
+        tuvw = np.array([time, u, v, w]).T
+        glpos = (0, 0, -85)
+        constraint_file = ConstraintFile(center_gl_xyz=(0, 0, -85), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        self.assertRaisesRegex(ValueError, "At time, t=0, global position \(0,0,-44\)", constraint_file.add_constraints, (0, 0, -85 + 35 + 6), tu)
+        self.assertRaisesRegex(ValueError, "At time, t=0, global position \(0,0,-126\)", constraint_file.add_constraints, (0, 0, -85 - 35 - 6), tu)
+        self.assertRaisesRegex(ValueError, "At time, t=0, global position \(-41,0,-85\)", constraint_file.add_constraints, (-35 - 6, 0, -85), tu)
+        self.assertRaisesRegex(ValueError, "At time, t=0, global position \(41,0,-85\)", constraint_file.add_constraints, (35 + 6, 0, -85), tu)
+        self.assertRaisesRegex(ValueError, "At time, t=0, global position \(0,2,-85\)", constraint_file.add_constraints, (0, 2, -85), tu)
+        self.assertRaisesRegex(ValueError, "At time, t=2, global position \(0,-13,-85\)", constraint_file.add_constraints, (0, -13, -85), tu)
+
+    def test_hawc2_cmd(self):
+        constraint_file = ConstraintFile(center_gl_xyz=(0, 0, -85), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        mann = constraint_file.hawc2_mann_section("test",1)
+        self.assertEqual(mann.box_dim_u.values, [16,1.875])
+        
+    def test_load(self):
+        constraint_file = ConstraintFile(center_gl_xyz=(-5, 4, -90), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.load(get_test_file('constraints_test.con'))
+        with open(get_test_file('constraints_test.con')) as fid:
+            self.assertEqual(str(constraint_file), fid.read())
+        
+    def test_time_series(self):
+        constraint_file = ConstraintFile(center_gl_xyz=(-5, 4, -90), box_transport_speed=10, no_grid_points=(16, 8, 8), box_dimension=(30, 70, 70))
+        constraint_file.load(get_test_file('constraints_test.con'))
+        time,uvw = constraint_file.time_series(-4)
+        u,v,w = uvw.T
+        m = ~np.isnan(u)
+        np.testing.assert_array_equal(time[m],[0,1,2])
+        np.testing.assert_array_equal(u[m],[-2,0,2])
+        
+if __name__ == "__main__":
+    #import sys;sys.argv = ['', 'Test.testConstraintFile']
+    unittest.main()
diff --git a/wetb/wind/turbulence/tests/test_files/constraints_test.con b/wetb/wind/turbulence/tests/test_files/constraints_test.con
new file mode 100644
index 0000000..600a34d
--- /dev/null
+++ b/wetb/wind/turbulence/tests/test_files/constraints_test.con
@@ -0,0 +1,3 @@
+3;5;5;u;-2.0000000000
+8;5;5;u;0.0000000000
+13;5;5;u;2.0000000000
\ No newline at end of file
-- 
GitLab