From ee113b352070d1ea763d04c4530616d81be026eb Mon Sep 17 00:00:00 2001
From: pcain-usgs <pcain@usgs.gov>
Date: Thu, 4 Feb 2021 10:59:28 -0700
Subject: [PATCH] Support legacy statefiles, add matrix process method

---
 etc/adjusted/adjbou_state_HE_.json      | 16 +++++----
 geomagio/adjusted/AdjustedMatrix.py     | 12 +++++++
 geomagio/algorithm/AdjustedAlgorithm.py | 45 +++++++++++++------------
 3 files changed, 45 insertions(+), 28 deletions(-)

diff --git a/etc/adjusted/adjbou_state_HE_.json b/etc/adjusted/adjbou_state_HE_.json
index f9c0e3d9d..4aa26dd35 100644
--- a/etc/adjusted/adjbou_state_HE_.json
+++ b/etc/adjusted/adjbou_state_HE_.json
@@ -1,8 +1,12 @@
 {
-    "matrix": [
-        [-1, 0, 0],
-        [0, -1, 0],
-        [0, 0, 1]
-    ],
-    "pier_correction": -22.0
+    "PC": -22,
+    "M11": -1,
+    "M12": 0,
+    "M13": 0,
+    "M21": 0,
+    "M22": -1,
+    "M23": 0,
+    "M31": 0,
+    "M32": 0,
+    "M33": 1
 }
\ No newline at end of file
diff --git a/geomagio/adjusted/AdjustedMatrix.py b/geomagio/adjusted/AdjustedMatrix.py
index b2647ff91..ff38990dd 100644
--- a/geomagio/adjusted/AdjustedMatrix.py
+++ b/geomagio/adjusted/AdjustedMatrix.py
@@ -1,3 +1,4 @@
+import numpy as np
 from obspy import UTCDateTime
 from pydantic import BaseModel
 from typing import Any, List, Optional
@@ -24,3 +25,14 @@ class AdjustedMatrix(BaseModel):
     metrics: Optional[List[Metric]] = None
     starttime: Optional[UTCDateTime] = None
     endtime: Optional[UTCDateTime] = None
+
+    def process(self, values: List[List[float]], outchannels=["X", "Y", "Z", "F"]):
+        """ Apply matrix to raw data. Apply pier correction to F when necessary """
+        data = np.vstack([values[0:3]] + [np.ones_like(values[0])])
+        adjusted = self.matrix @ data
+        if "F" in outchannels:
+            f = values[-1] + self.pier_correction
+            adjusted = np.vstack([adjusted[0 : len(outchannels) - 1]] + [f])
+        else:
+            adjusted = adjusted[0 : len(outchannels)]
+        return adjusted
diff --git a/geomagio/algorithm/AdjustedAlgorithm.py b/geomagio/algorithm/AdjustedAlgorithm.py
index adc4b1521..78a38ae25 100644
--- a/geomagio/algorithm/AdjustedAlgorithm.py
+++ b/geomagio/algorithm/AdjustedAlgorithm.py
@@ -43,24 +43,33 @@ class AdjustedAlgorithm(Algorithm):
         """Load algorithm state from a file.
         File name is self.statefile.
         """
-        pier_correction = 0
         if self.statefile is None:
             return
-        # Adjusted matrix defaults to identity matrix
-        matrix_size = len([c for c in self.get_input_channels() if c != "F"]) + 1
-        matrix = np.eye(matrix_size)
-        data = None
         try:
             with open(self.statefile, "r") as f:
                 data = f.read()
                 data = json.loads(data)
         except IOError as err:
-            sys.stderr.write("I/O error {0}".format(err))
-        if data is None or data == "":
-            return
-        self.matrix = AdjustedMatrix(
-            matrix=np.array(data["matrix"]), pier_correction=data["pier_correction"]
-        )
+            raise FileNotFoundError("statefile not found")
+        pier_correction = 0
+        # Adjusted matrix defaults to identity matrix
+        matrix_size = len([c for c in self.get_input_channels() if c != "F"]) + 1
+        matrix = np.eye(matrix_size)
+        if self.statefile is not None:
+            try:
+                if "pier_correction" in data.keys():
+                    # read data
+                    matrix = np.array(data["matrix"])
+                    pier_correction = data["pier_correction"]
+                if "PC" in data.keys():
+                    # read data from legacy format
+                    for row in range(matrix_size):
+                        for col in range(matrix_size):
+                            matrix[row, col] = np.float64(data[f"M{row+1}{col+1}"])
+                    pier_correction = np.float64(data["PC"])
+            except:
+                raise KeyError("matrix and pier correction not found in statefile")
+        self.matrix = AdjustedMatrix(matrix=matrix, pier_correction=pier_correction)
 
     def save_state(self):
         """Save algorithm state to a file.
@@ -123,14 +132,9 @@ class AdjustedAlgorithm(Algorithm):
         inchannels = self.get_input_channels()
         outchannels = self.get_output_channels()
         raws = np.vstack(
-            [
-                stream.select(channel=channel)[0].data
-                for channel in inchannels
-                if channel != "F"
-            ]
-            + [np.ones_like(stream[0].data)]
+            [stream.select(channel=channel)[0].data for channel in inchannels]
         )
-        adjusted = np.matmul(self.matrix.matrix, raws)
+        adjusted = self.matrix.process(values=raws, outchannels=outchannels)
         out = Stream(
             [
                 self.create_trace(
@@ -138,12 +142,9 @@ class AdjustedAlgorithm(Algorithm):
                     stream.select(channel=inchannels[i])[0].stats,
                     adjusted[i],
                 )
-                for i in range(len(adjusted) - 1)
+                for i in range(len(adjusted))
             ]
         )
-        if "F" in inchannels and "F" in outchannels:
-            f = stream.select(channel="F")[0]
-            out += self.create_trace("F", f.stats, f.data + self.matrix.pier_correction)
         return out
 
     def can_produce_data(self, starttime, endtime, stream):
-- 
GitLab