From c59c31602b07f8d1eec738068548ed11ba718600 Mon Sep 17 00:00:00 2001 From: pcain-usgs <pcain@usgs.gov> Date: Mon, 25 Jan 2021 13:13:43 -0700 Subject: [PATCH] Capture log number metric --- geomagio/adjusted/AdjustedMatrix.py | 3 ++- geomagio/adjusted/Affine.py | 8 +++++--- geomagio/adjusted/Transform.py | 27 ++++++++++++++++----------- test/adjusted_test/adjusted_test.py | 19 ++++++++++++++++++- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/geomagio/adjusted/AdjustedMatrix.py b/geomagio/adjusted/AdjustedMatrix.py index 980d44d1d..5913d2a5a 100644 --- a/geomagio/adjusted/AdjustedMatrix.py +++ b/geomagio/adjusted/AdjustedMatrix.py @@ -1,6 +1,6 @@ from obspy import UTCDateTime from pydantic import BaseModel -from typing import Optional, Any +from typing import Optional, Any, List from .. import pydantic_utcdatetime @@ -20,5 +20,6 @@ class AdjustedMatrix(BaseModel): matrix: Any pier_correction: float + metrics: List[float] = [0.0, 0.0] starttime: Optional[UTCDateTime] = None endtime: Optional[UTCDateTime] = None diff --git a/geomagio/adjusted/Affine.py b/geomagio/adjusted/Affine.py index 183b8a8e4..ffd395afd 100644 --- a/geomagio/adjusted/Affine.py +++ b/geomagio/adjusted/Affine.py @@ -245,7 +245,7 @@ class Affine(BaseModel): times = self.get_times(readings) Ms = [] weights = [] - + metrics = [] inputs = ordinates for transform in self.transforms: @@ -268,7 +268,7 @@ class Affine(BaseModel): inputs = np.dot( M, np.vstack([inputs[0], inputs[1], inputs[2], np.ones_like(inputs[0])]) )[0:3] - + metrics.append(transform.metric) Ms.append(M) # compose affine transform matrices using reverse ordered matrices @@ -277,7 +277,9 @@ class Affine(BaseModel): [reading.pier_correction for reading in readings], weights=weights ) - return AdjustedMatrix(matrix=M_composed, pier_correction=pier_correction) + return AdjustedMatrix( + matrix=M_composed, pier_correction=pier_correction, metrics=metrics + ) def get_weights( self, diff --git a/geomagio/adjusted/Transform.py b/geomagio/adjusted/Transform.py index 9937cb583..dd98f1b67 100644 --- a/geomagio/adjusted/Transform.py +++ b/geomagio/adjusted/Transform.py @@ -13,8 +13,13 @@ class Transform(object): Defaults to infinite(equal weighting) """ - def __init__(self, memory: float = np.inf): + def __init__(self, memory: float = np.inf, metric: float = 0.0): self.memory = memory + self.metric = metric + + def update_metric(self, sigma): + # indicates the maximum possible number of lost significant values + self.metric = np.log(abs(sigma[0] / sigma[-1])) def get_weights(self, times: UTCDateTime, time: int = None) -> List[float]: """ @@ -176,7 +181,7 @@ class NoConstraints(LeastSq): # regression matrix M that minimizes L2 norm M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T) - + self.update_metric(sigma) if rank < 3: print("Poorly conditioned or singular matrix, returning NaNs") return np.nan * np.ones((4, 4)) @@ -222,7 +227,7 @@ class ZRotationShear(LeastSq): # regression matrix M that minimizes L2 norm M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T) - + self.update_metric(sigma) if rank < 3: print("Poorly conditioned or singular matrix, returning NaNs") return np.nan * np.ones((4, 4)) @@ -269,7 +274,7 @@ class ZRotationHscale(LeastSq): # regression matrix M that minimizes L2 norm M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T) - + self.update_metric(sigma) if rank < 3: print("Poorly conditioned or singular matrix, returning NaNs") return np.nan * np.ones((4, 4)) @@ -316,7 +321,7 @@ class ZRotationHscaleZbaseline(LeastSq): # regression matrix M that minimizes L2 norm M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T) - + self.update_metric(sigma) if rank < 3: print("Poorly conditioned or singular matrix, returning NaNs") return np.nan * np.ones((4, 4)) @@ -360,7 +365,7 @@ class RotationTranslation3D(SVD): # Singular value decomposition, then rotation matrix from L&R eigenvectors # (the determinant guarantees a rotation, and not a reflection) U, S, Vh = np.linalg.svd(H) - + self.update_metric(S) if np.sum(S) < 3: print("Poorly conditioned or singular matrix, returning NaNs") return np.nan * np.ones((4, 4)) @@ -410,7 +415,7 @@ class Rescale3D(LeastSq): # regression matrix M that minimizes L2 norm M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T) - + self.update_metric(sigma) if rank < 3: print("Poorly conditioned or singular matrix, returning NaNs") return np.nan * np.ones((4, 4)) @@ -465,7 +470,7 @@ class TranslateOrigins(LeastSq): # regression matrix M that minimizes L2 norm M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T) - + self.update_metric(sigma) if rank < 3: print("Poorly conditioned or singular matrix, returning NaNs") return np.nan * np.ones((4, 4)) @@ -505,7 +510,7 @@ class ShearYZ(LeastSq): abs_stacked = self.get_weighted_values(values=abs_stacked, weights=weights) # regression matrix M that minimizes L2 norm M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T) - + self.update_metric(sigma) if rank < 3: print("Poorly conditioned or singular matrix, returning NaNs") return np.nan * np.ones((4, 4)) @@ -554,7 +559,7 @@ class RotationTranslationXY(SVD): # Singular value decomposition, then rotation matrix from L&R eigenvectors # (the determinant guarantees a rotation, and not a reflection) U, S, Vh = np.linalg.svd(H) - + self.update_metric(S) if np.sum(S) < 2: print("Poorly conditioned or singular matrix, returning NaNs") return np.nan * np.ones((4, 4)) @@ -637,7 +642,7 @@ class QRFactorization(SVD): # regression matrix M that minimizes L2 norm M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T) - + self.update_metric(sigma) if rank < 2: print("Poorly conditioned or singular matrix, returning NaNs") return np.nan * np.ones((4, 4)) diff --git a/test/adjusted_test/adjusted_test.py b/test/adjusted_test/adjusted_test.py index d37c3aa04..eaebd4471 100644 --- a/test/adjusted_test/adjusted_test.py +++ b/test/adjusted_test/adjusted_test.py @@ -1,6 +1,6 @@ import json import numpy as np -from numpy.testing import assert_equal, assert_array_almost_equal +from numpy.testing import assert_equal, assert_array_almost_equal, assert_array_less from obspy.core import UTCDateTime from geomagio.adjusted.SpreadsheetSummaryFactory import SpreadsheetSummaryFactory @@ -235,6 +235,7 @@ def test_BOU201911202001_short_causal(): ).calculate(readings=readings) matrices = format_result([adjusted_matrix.matrix for adjusted_matrix in result]) + metrics = [adjusted_matrix.metrics for adjusted_matrix in result] expected_matrices = get_excpected_matrices("BOU", "short_causal") for i in range(len(matrices)): assert_array_almost_equal( @@ -243,6 +244,7 @@ def test_BOU201911202001_short_causal(): decimal=3, err_msg=f"Matrix {i} not equal", ) + assert_array_less(metrics[i], 5.0) assert_equal(len(matrices), ((endtime - starttime) // update_interval) + 1) @@ -265,6 +267,7 @@ def test_BOU201911202001_short_acausal(): ) matrices = format_result([adjusted_matrix.matrix for adjusted_matrix in result]) + metrics = [adjusted_matrix.metrics for adjusted_matrix in result] expected_matrices = get_excpected_matrices("BOU", "short_acausal") for i in range(len(matrices)): assert_array_almost_equal( @@ -273,6 +276,7 @@ def test_BOU201911202001_short_acausal(): decimal=3, err_msg=f"Matrix {i} not equal", ) + assert_array_less(metrics[i], 5.0) assert_equal(len(matrices), ((endtime - starttime) // update_interval) + 1) @@ -299,6 +303,7 @@ def test_BOU201911202001_infinite_weekly(): ) matrices = format_result([adjusted_matrix.matrix for adjusted_matrix in result]) + metrics = [adjusted_matrix.metrics for adjusted_matrix in result] expected_matrices = get_excpected_matrices("BOU", "inf_weekly") for i in range(len(matrices)): assert_array_almost_equal( @@ -307,6 +312,7 @@ def test_BOU201911202001_infinite_weekly(): decimal=3, err_msg=f"Matrix {i} not equal", ) + assert_array_less(metrics[i], 5.0) assert_equal(len(matrices), ((endtime - starttime) // update_interval) + 1) @@ -327,6 +333,7 @@ def test_BOU201911202001_infinite_one_interval(): ) matrices = format_result([adjusted_matrix.matrix for adjusted_matrix in result]) + metrics = [adjusted_matrix.metrics for adjusted_matrix in result] expected_matrices = get_excpected_matrices("BOU", "inf_one_interval") for i in range(len(matrices)): assert_array_almost_equal( @@ -335,6 +342,7 @@ def test_BOU201911202001_infinite_one_interval(): decimal=3, err_msg=f"Matrix {i} not equal", ) + assert_array_less(metrics[i], 5.0) assert_equal(len(matrices), 1) @@ -362,6 +370,7 @@ def test_CMO2015_causal(): ) matrices = format_result([adjusted_matrix.matrix for adjusted_matrix in result]) + metrics = [adjusted_matrix.metrics for adjusted_matrix in result] expected_matrices = get_excpected_matrices("CMO", "short_causal") for i in range(len(matrices)): assert_array_almost_equal( @@ -370,6 +379,7 @@ def test_CMO2015_causal(): decimal=3, err_msg=f"Matrix {i} not equal", ) + assert_array_less(metrics[i], 5.0) assert_equal(len(matrices), ((endtime - starttime) // update_interval) + 1) @@ -398,6 +408,7 @@ def test_CMO2015_acausal(): ) matrices = format_result([adjusted_matrix.matrix for adjusted_matrix in result]) + metrics = [adjusted_matrix.metrics for adjusted_matrix in result] expected_matrices = get_excpected_matrices("CMO", "short_acausal") for i in range(len(matrices)): assert_array_almost_equal( @@ -406,6 +417,7 @@ def test_CMO2015_acausal(): decimal=3, err_msg=f"Matrix {i} not equal", ) + assert_array_less(metrics[i], 5.0) assert_equal(len(matrices), ((endtime - starttime) // update_interval) + 1) @@ -438,6 +450,7 @@ def test_CMO2015_infinite_weekly(): ) matrices = format_result([adjusted_matrix.matrix for adjusted_matrix in result]) + metrics = [adjusted_matrix.metrics for adjusted_matrix in result] expected_matrices = get_excpected_matrices("CMO", "inf_weekly") for i in range(len(matrices)): assert_array_almost_equal( @@ -446,6 +459,7 @@ def test_CMO2015_infinite_weekly(): decimal=3, err_msg=f"Matrix {i} not equal", ) + assert_array_less(metrics[i], 5.0) assert_equal(len(matrices), ((endtime - starttime) // update_interval) + 1) @@ -474,6 +488,7 @@ def test_CMO2015_infinite_one_interval(): ) matrices = format_result([adjusted_matrix.matrix for adjusted_matrix in result]) + metrics = [adjusted_matrix.metrics for adjusted_matrix in result] expected_matrices = get_excpected_matrices("CMO", "inf_one_interval") for i in range(len(matrices)): assert_array_almost_equal( @@ -482,4 +497,6 @@ def test_CMO2015_infinite_one_interval(): decimal=3, err_msg=f"Matrix {i} not equal", ) + assert_array_less(metrics[i], 5.0) + assert_equal(len(matrices), 1) -- GitLab