From 8e19c4b51518cdf2fd9fb22394730e507391bd5b Mon Sep 17 00:00:00 2001
From: madsmpedersen <m@madsp.dk>
Date: Thu, 5 Nov 2015 12:23:17 +0100
Subject: [PATCH] added sel_file.py + tests/test_sel_file.py

---
 wetb/hawc2/sel_file.py            | 134 ++++++++++++++++++++++++++++++
 wetb/hawc2/tests/test_sel_file.py |  50 +++++++++++
 2 files changed, 184 insertions(+)
 create mode 100644 wetb/hawc2/sel_file.py
 create mode 100644 wetb/hawc2/tests/test_sel_file.py

diff --git a/wetb/hawc2/sel_file.py b/wetb/hawc2/sel_file.py
new file mode 100644
index 0000000..f6f0e6a
--- /dev/null
+++ b/wetb/hawc2/sel_file.py
@@ -0,0 +1,134 @@
+from datetime import datetime
+import os
+import numpy as np
+
+
+BINARY = "BINARY"
+ASCII = "ASCII"
+class SelFile():
+    """Class for reading HAWC2 sel-files
+    Attributes
+    ----------
+    version_id : str
+        Version id
+    created : datetime.datetime
+        Date and Time of creation
+    result_file : str
+        Result file name read from file. Note that dat-filename are often used instead
+    dat_filename : str
+        Result file name (sel-basename + ".dat")
+    scans : int
+        Number of observations/rows/scans
+    channels : int
+        Number of channels/sensors/columns (same as 'no_sensors')
+    no_sensors : int
+        Number of channels/sensors/columns (same as 'channels')
+    time : float
+        Duration of simulation (same as duration)
+    duration : float
+        Duration of simulation (same as time)
+    format : {"BINARY", "ASCII"}
+        Result file format
+    sensors : array_like
+        List of (id, name, unit, description)-tuples
+    scalefactors : array_like
+        Array of scale factors. Only if format is BINARY
+    """
+
+    def __init__(self, sel_filename):
+        if not os.path.isfile(sel_filename) or os.path.splitext(sel_filename)[1] != ".sel":
+            raise Warning("%s cannot be found or is not a legal *.sel file" % os.path.realpath(sel_filename))
+        with open(sel_filename) as f:
+            lines = f.readlines()
+
+
+        # parse info lines
+        def val(line):
+            return line.split(" : ")[1].strip()
+        try:
+            self.version_id = val(lines[1])
+            _created = "%s %s" % (val(lines[3]), val(lines[2]))
+            self.created = datetime.strptime(_created, "%d:%m.%Y %H:%M:%S")
+            self.result_file = os.path.basename(val(lines[5]))
+
+        except:
+            pass
+
+        self.dat_filename = sel_filename[:-4] + ".dat"
+
+        _info = lines[8].split()
+        self.scans = int(_info[0])
+        self.no_sensors = self.channels = int(_info[1])
+        self.duration = self.time = float(_info[2])
+        if len(_info) > 3:
+            self.format = _info[3].upper()
+        elif self.no_sensors * self.scans * 2 == os.path.getsize(self.dat_filename):
+            self.format = "BINARY"
+        else:
+            self.format = "ASCII"
+
+        # parse sensor info
+        self.sensors = []
+        for i, line in enumerate(lines[12:12 + self.no_sensors]):
+            try:
+                ch = int(line[:7])
+                name = str(line[7:43]).strip()
+                unit = str(line[43:48]).strip()
+                description = str(line[49:]).strip()
+                self.sensors.append((ch, name, unit, description))
+            except ValueError:
+                raise Warning("Value error in '%s'\nLine %d supposed to contain number, name, unit and description of sensor %d, but contained:\n%s" % (sel_filename, i + 13, i, line.strip()))
+
+        # parse scalefactors
+        if self.format == "BINARY":
+            self.scale_factors = np.array([float(factor) for factor in lines[12 + self.no_sensors + 2:]])
+
+
+def save(sel_filename, version, time, scans, no_sensors, duration, sensors, scale_factors=None):
+    """Create HAWC2 sel-file
+
+    Parameters
+    ----------
+    sel_filename : str
+        Filename
+    version : str
+        Version tag
+    time : datetime.datetime
+        Date and time of creation
+    scans : int
+        Number of scans/observations/rows
+    no_sensors : int
+        Number of sensors/channels/columns
+    duration : int, float
+        Duration of simulation
+    sensors : array_like
+        List of (name, unit, description)-tuples
+    scale_factors : array_like, optional
+        Array of scale factors. Only for BINARY format
+    """
+    lines = []
+    linesep = "_" * 120
+    lines.append(linesep)
+    lines.append("  Version ID : %s" % version)
+    lines.append(" " * 60 + "Time : %s" % time.strftime("%H:%M:%S"))
+    lines.append(" " * 60 + "Date : %s" % time.strftime("%d:%m.%Y"))
+    lines.append(linesep)
+    lines.append("  Result file : %s.dat" % sel_filename[:-4])
+    lines.append(linesep)
+    lines.append("   Scans    Channels    Time [sec]      Format")
+    lines.append("   %8s    %3s       %8.3f       %s" % (scans, no_sensors, duration, ("BINARY", "ASCII")[scale_factors is None]))
+    lines.append("")
+    lines.append('  Channel   Variable Description               ')
+    lines.append("")
+    for nr, sensor in enumerate(sensors, 1):
+        name, unit, description = sensor
+        lines.append("  %4s      %-30s %-10s %s" % (nr, name[:30], unit[:10], description[:512]))
+    lines.append(linesep)
+    if scale_factors is not None:
+        lines.append("Scale factors:")
+        for sf in scale_factors:
+            lines.append("  %.5E" % sf)
+
+    with open(sel_filename, 'w') as f:
+        f.write("\n".join(lines))
+
diff --git a/wetb/hawc2/tests/test_sel_file.py b/wetb/hawc2/tests/test_sel_file.py
new file mode 100644
index 0000000..a96be5d
--- /dev/null
+++ b/wetb/hawc2/tests/test_sel_file.py
@@ -0,0 +1,50 @@
+'''
+Created on 17/07/2014
+
+@author: MMPE
+'''
+import unittest
+from wetb.hawc2.sel_file import SelFile, BINARY, ASCII
+from datetime import datetime
+
+
+class Test(unittest.TestCase):
+
+    def setUp(self):
+        unittest.TestCase.setUp(self)
+        self.testfilepath = "test_files/hawc2io/"
+
+    def test_sel_file_ascii(self):
+        sf = SelFile(self.testfilepath + "Hawc2ascii.sel")
+        self.assertEqual(sf.version_id, "HAWC2AERO 2.4w")
+        self.assertEqual(sf.created, datetime(2013, 1, 24, 10, 2, 19))
+        self.assertEqual(sf.result_file, "Hawc2ascii.dat")
+        self.assertEqual(sf.scans, 800)
+        self.assertEqual(sf.channels, 28)
+        self.assertEqual(sf.no_sensors, 28)
+        self.assertEqual(sf.duration, 20)
+        self.assertEqual(sf.time, 20)
+        self.assertEqual(sf.format, ASCII)
+        self.assertEqual(sf.sensors[0], (1, 'Time', 's', 'Time'))
+        self.assertEqual(sf.sensors[1], (2, 'WSP gl. coo.,Vy', 'm/s', 'Free wind speed Vy, gl. coo, of gl. pos    2.50,  -1.00, -47.50'))
+
+
+    def test_sel_file_bin(self):
+        sf = SelFile(self.testfilepath + "Hawc2bin.sel")
+        self.assertEqual(sf.version_id, "HAWC2AERO 2.4w")
+        self.assertEqual(sf.created, datetime(2013, 1, 24, 10, 4, 37))
+        self.assertEqual(sf.result_file, "Hawc2bin.dat")
+        self.assertEqual(sf.scans, 800)
+        self.assertEqual(sf.channels, 28)
+        self.assertEqual(sf.no_sensors, 28)
+        self.assertEqual(sf.duration, 20)
+        self.assertEqual(sf.time, 20)
+        self.assertEqual(sf.format, BINARY)
+        self.assertEqual(sf.sensors[0], (1, 'Time', 's', 'Time'))
+        self.assertEqual(sf.sensors[1], (2, 'WSP gl. coo.,Vy', 'm/s', 'Free wind speed Vy, gl. coo, of gl. pos    2.50,  -1.00, -47.50'))
+        self.assertEqual(sf.scale_factors[0], 6.25000E-04)
+        self.assertEqual(sf.scale_factors[1], 5.65540E-02)
+
+if __name__ == "__main__":
+    #import sys;sys.argv = ['', 'Test.testName']
+    unittest.main()
-- 
GitLab