From 68d5d5ab6a66f044939ac936da3f7832f37e4835 Mon Sep 17 00:00:00 2001 From: pcain-usgs <pcain@usgs.gov> Date: Thu, 13 May 2021 17:33:56 -0600 Subject: [PATCH 1/7] SNCL/SNCLFactory --- geomagio/edge/SNCL.py | 114 ++++++++++ geomagio/edge/SNCLFactory.py | 83 ++++++++ geomagio/edge/__init__.py | 6 + geomagio/edge/sncl.py | 258 ----------------------- test/edge_test/SNCLFactory_test.py | 66 ++++++ test/edge_test/SNCL_test.py | 328 +++++++++++++++++++++++++++++ 6 files changed, 597 insertions(+), 258 deletions(-) create mode 100644 geomagio/edge/SNCL.py create mode 100644 geomagio/edge/SNCLFactory.py delete mode 100644 geomagio/edge/sncl.py create mode 100644 test/edge_test/SNCLFactory_test.py create mode 100644 test/edge_test/SNCL_test.py diff --git a/geomagio/edge/SNCL.py b/geomagio/edge/SNCL.py new file mode 100644 index 000000000..20a0a885f --- /dev/null +++ b/geomagio/edge/SNCL.py @@ -0,0 +1,114 @@ +from typing import Dict, Optional, Set + +from pydantic import BaseModel + +INTERVAL_CONVERSIONS = { + "legacy": { + "second": "S", + "minute": "M", + "hour": "H", + "day": "D", + }, + "miniseed": { + "tenhertz": "B", + "second": "L", + "minute": "U", + "hour": "R", + "day": "P", + }, +} +ELEMENT_CONVERSIONS = { + # e-field + "E-E": "QE", + "E-N": "QN", + # derived indicies + "Dst3": "X3", + "Dst4": "X4", + "SQ": "SQ", + "SV": "SV", + "DIST": "DT", + "DST": "GD", +} + +CHANNEL_CONVERSIONS = { + ELEMENT_CONVERSIONS[key]: key for key in ELEMENT_CONVERSIONS.keys() +} + + +class SNCL(BaseModel): + station: str + network: str = "NT" + channel: str + location: str + data_format: str = "miniseed" + + def dict(self, exclude: Set = {"data_format"}) -> dict: + return super().dict( + exclude=exclude, + ) + + def json(self, exclude: Set = {"data_format"}) -> str: + return super().json( + exclude=exclude, + ) + + @property + def data_type(self) -> str: + location_start = self.location[0] + if location_start == "R": + return "variation" + elif location_start == "A": + return "adjusted" + elif location_start == "Q": + return "quasi-definitive" + elif location_start == "D": + return "definitive" + raise ValueError(f"Unexpected location start: {location_start}") + + @property + def element(self) -> str: + element = self.__get_predefined_element() + element = element or self.__get_element() + return element + + @property + def interval(self) -> str: + interval_conversions = INTERVAL_CONVERSIONS[self.data_format] + interval_code_conversions = { + interval_conversions[key]: key for key in interval_conversions.keys() + } + channel_start = self.channel[0] + try: + return interval_code_conversions[channel_start] + except: + raise ValueError(f"Unexcepted interval code: {channel_start}") + + def __get_element(self): + element_start = self.channel[2] + channel = self.channel + channel_middle = channel[1] + location_end = self.location[1] + if channel_middle in ["Q", "E"]: + element_end = "_Volt" + elif channel_middle == "Y": + element_end = "_Bin" + elif channel_middle == "K": + element_end = "_Temp" + elif location_end == "1": + element_end = "_Sat" + elif location_end == "D": + element_end = "_Dist" + elif location_end == "Q": + element_end = "_SQ" + elif location_end == "V": + element_end = "_SV" + else: + element_end = "" + return element_start + element_end + + def __get_predefined_element(self) -> Optional[str]: + channel = self.channel + channel_end = channel[1:] + if channel_end in CHANNEL_CONVERSIONS: + return CHANNEL_CONVERSIONS[channel_end] + return None diff --git a/geomagio/edge/SNCLFactory.py b/geomagio/edge/SNCLFactory.py new file mode 100644 index 000000000..4e677c0af --- /dev/null +++ b/geomagio/edge/SNCLFactory.py @@ -0,0 +1,83 @@ +from typing import Optional + +from .SNCL import SNCL, INTERVAL_CONVERSIONS, ELEMENT_CONVERSIONS + + +class SNCLFactory(object): + def __init__(self, data_format: str = "miniseed"): + self.data_format = data_format + + def get_sncl( + self, + station: str, + data_type: str, + element: str, + interval: str, + network: str = "NT", + ) -> SNCL: + return SNCL( + station=station, + network=network, + channel=self.get_channel(element=element, interval=interval), + location=self.get_location(element=element, data_type=data_type), + ) + + def get_channel(self, element: str, interval: str) -> str: + channel_start = self.__get_channel_start(interval=interval) + channel_end = self.__get_predefined_channel(element=element) + channel_end = channel_end or self.__get_channel_end(element=element) + return channel_start + channel_end + + def get_location(self, element: str, data_type: str) -> str: + location_start = self.__get_location_start(data_type=data_type) + location_end = self.__get_location_end(element=element) + return location_start + location_end + + def __get_channel_start(self, interval: str) -> str: + try: + return INTERVAL_CONVERSIONS[self.data_format][interval] + except: + raise ValueError(f"Unexpected interval: {interval}") + + def __get_predefined_channel(self, element: str) -> Optional[str]: + if len(element) == 3 and "-" not in element and element != "DST": + return element[1:] + elif element in ELEMENT_CONVERSIONS: + return ELEMENT_CONVERSIONS[element] + else: + return None + + def __get_channel_end(self, element: str) -> str: + channel_middle = "F" if self.data_format == "miniseed" else "V" + if "_Volt" in element: + channel_middle = "E" + elif "_Bin" in element: + channel_middle = "Y" + elif "_Temp" in element: + channel_middle = "K" + elif element in ["F", "G"] and self.data_format == "legacy": + channel_middle = "S" + channel_end = element.split("_")[0] + return channel_middle + channel_end + + def __get_location_start(self, data_type: str) -> str: + if data_type == "variation": + return "R" + elif data_type == "adjusted": + return "A" + elif data_type == "quasi-definitive": + return "Q" + elif data_type == "definitive": + return "D" + raise ValueError(f"Unexpected data type: {data_type}") + + def __get_location_end(self, element: str) -> str: + if "_Sat" in element: + return "1" + if "_Dist" in element: + return "D" + if "_SQ" in element: + return "Q" + if "_SV" in element: + return "V" + return "0" diff --git a/geomagio/edge/__init__.py b/geomagio/edge/__init__.py index 2a53748a1..bf808a25a 100644 --- a/geomagio/edge/__init__.py +++ b/geomagio/edge/__init__.py @@ -7,6 +7,8 @@ from .LocationCode import LocationCode from .MiniSeedFactory import MiniSeedFactory from .MiniSeedInputClient import MiniSeedInputClient from .RawInputClient import RawInputClient +from .SNCL import SNCL +from .SNCLFactory import SNCLFactory __all__ = [ "EdgeFactory", @@ -14,4 +16,8 @@ __all__ = [ "MiniSeedFactory", "MiniSeedInputClient", "RawInputClient", + "LegacySNCL", + "LegacySNIDE", + "SNCL", + "SNCLFactory", ] diff --git a/geomagio/edge/sncl.py b/geomagio/edge/sncl.py deleted file mode 100644 index 5bfa4ff2e..000000000 --- a/geomagio/edge/sncl.py +++ /dev/null @@ -1,258 +0,0 @@ -"""SNCL utilities. - -Station -Network -Channel -Location -""" - -# components that map directly to channel suffixes -CHANNEL_FROM_COMPONENT = { - # e-field - "E-E": "QY", - "E-N": "QX", - "E-U": "QU", - "E-V": "QV", - # derived indicies - "AE": "XA", - "DST3": "X3", - "DST": "X4", - "K": "XK", -} -# reverse lookup of component from channel -COMPONENT_FROM_CHANNEL = dict((v, k) for (k, v) in CHANNEL_FROM_COMPONENT.iteritems()) - - -class SNCLException(Exception): - pass - - -def get_scnl( - observatory, - component=None, - channel=None, - data_type="variation", - interval="second", - location=None, - network="NT", -): - """Generate a SNCL code from data attributes. - - Parameters - ---------- - observatory : str - observatory code. - component : str - geomag component name. - channel : str - default None. - use a specific channel code, instead of generating. - data_type : str - default 'variation' - 'variation', 'adjusted', 'quasi-definitive', or 'definitive'. - interval: str|float - default 'second' - 'tenhertz', 'second', 'minute', 'hour', 'day', - or equivalent interval in seconds - location : str - default None - use a specific location code, instead of generating. - network : str - default 'NT' - network `observatory` is a part of. - - Raises - ------ - SNCLException : when unable to generate a SNCL - - Returns - ------- - dict : dictionary containing the following keys - 'station' : observatory code - 'network' : network code - 'channel' : channel code - 'location' : location code - """ - # use explicit channel/location if specified - channel = channel or __get_channel(component, interval) - location = location or __get_location(component, data_type) - return { - "station": observatory, - "network": network, - "channel": channel, - "location": location, - } - - -def parse_sncl(sncl): - """Parse a SNCL code into data attributes. - - Parameters - ---------- - sncl : dict - dictionary object with the following keys - 'station' : observatory code - 'network' : network code - 'channel' : channel code - 'location' : location code - - Raises - ------ - SNCLException : when unable to parse a SNCL - - Returns - ------- - dict : dictionary containing the following keys - 'observatory' : observatory code - 'network' : network code - 'component' : geomag component name - 'data_type' : geomag data type (e.g. 'variation') - 'interval' : data interval in seconds (e.g. 1) - """ - network = sncl["network"] - station = sncl["station"] - channel = sncl["channel"] - location = sncl["location"] - return { - "observatory": station, - "network": network, - "component": __parse_component(channel, location), - "data_type": __parse_data_type(location), - "interval": __parse_interval(channel), - } - - -def __get_channel(component, interval): - channel_start = __get_channel_start(interval) - # check for direct component mappings - if component in CHANNEL_FROM_COMPONENT: - channel_end = CHANNEL_FROM_COMPONENT[component] - else: - channel_end = __get_channel_end(component) - return channel_start + channel_end - - -def __get_channel_start(interval): - if interval == "tenhertz" or interval == 0.1: - return "B" - if interval == "second" or interval == 1: - return "L" - if interval == "minute" or interval == 60: - return "U" - if interval == "hour" or interval == 3600: - return "R" - if interval == "day" or interval == 86400: - return "P" - raise SNCLException("Unexpected interval {}".format(interval)) - - -def __get_channel_end(component): - # default to engineering units - channel_middle = "F" - # check for suffix that may override - component_parts = component.split("-") - channel_end = component_parts[0] - if len(component_parts) > 1: - component_suffix = component_parts[1] - if component_suffix == "-Bin": - channel_middle = "Y" - elif component_suffix == "-Temp": - channel_middle = "K" - elif component_suffix == "-Volt": - channel_middle = "E" - else: - raise SNCLException("Unexpected component {}".format(component)) - return channel_middle + channel_end - - -def __get_location(component, data_type): - location_start = __get_location_start(data_type) - location_end = __get_location_end(component) - return location_start + location_end - - -def __get_location_start(data_type): - if data_type == "variation": - return "R" - elif data_type == "adjusted": - return "A" - elif data_type == "quasi-definitive": - return "Q" - elif data_type == "definitive": - return "D" - raise SNCLException("Unexpected data type {}".format(data_type)) - - -def __get_location_end(component): - if component.endswith("-Sat"): - return "1" - if component.endswith("-Dist"): - return "D" - if component.endswith("-SQ"): - return "Q" - if component.endswith("-SV"): - return "V" - return "0" - - -def __parse_component(channel, location): - channel_end = channel[1:] - if channel_end in COMPONENT_FROM_CHANNEL: - return COMPONENT_FROM_CHANNEL[channel_end] - channel_middle = channel[1] - component = channel[2] - component_end = "" - if channel_middle == "E": - component_end = "-Volt" - elif channel_middle == "K": - component_end = "-Temp" - elif channel_middle == "Y": - component_end = "-Bin" - elif channel_middle == "F": - component_end = __parse_component_end(location) - else: - raise SNCLException("Unexpected channel middle {}".format(channel)) - return component + component_end - - -def __parse_component_end(location): - location_end = location[1] - if location_end == "0": - return "" - if location_end == "1": - return "-Sat" - if location_end == "D": - return "-Dist" - if location_end == "Q": - return "-SQ" - if location_end == "V": - return "-SV" - raise SNCLException("Unexpected location end {}".format(location_end)) - - -def __parse_data_type(location): - location_start = location[0] - if location_start == "R": - return "variation" - if location_start == "A": - return "adjusted" - if location_start == "Q": - return "quasi-definitive" - if location_start == "D": - return "definitive" - raise SNCLException("Unexpected location start {}".format(location_start)) - - -def __parse_interval(channel): - channel_start = channel[0] - if channel_start == "B": - return 0.1 - if channel_start == "L": - return 1 - if channel_start == "U": - return 60 - if channel_start == "R": - return 3600 - if channel_start == "P": - return 86400 - raise SNCLException("Unexpected channel {}".format(channel)) diff --git a/test/edge_test/SNCLFactory_test.py b/test/edge_test/SNCLFactory_test.py new file mode 100644 index 000000000..d12ab5f47 --- /dev/null +++ b/test/edge_test/SNCLFactory_test.py @@ -0,0 +1,66 @@ +from geomagio.edge import SNCL, SNCLFactory + + +def test_get_sncl(): + assert ( + SNCLFactory(data_format="miniseed").get_sncl( + station="BOU", + data_type="variation", + element="UFU", + interval="minute", + ) + == SNCL(station="BOU", network="NT", channel="UFU", location="R0") + ) + assert ( + SNCLFactory(data_format="legacy").get_sncl( + station="BOU", + data_type="variation", + element="MVH", + interval="minute", + ) + == SNCL(station="BOU", network="NT", channel="MVH", location="R0") + ) + + +def test_get_channel(): + # test miniseed format + factory = SNCLFactory(data_format="miniseed") + assert factory.get_channel(element="D", interval="minute") == "UFD" + assert factory.get_channel(element="F", interval="minute") == "UFF" + assert factory.get_channel(element="H", interval="minute") == "UFH" + assert factory.get_channel(element="Dst4", interval="minute") == "UX4" + assert factory.get_channel(element="Dst3", interval="minute") == "UX3" + assert factory.get_channel(element="E-E", interval="minute") == "UQE" + assert factory.get_channel(element="E-N", interval="minute") == "UQN" + assert factory.get_channel(element="SQ", interval="minute") == "USQ" + assert factory.get_channel(element="SV", interval="minute") == "USV" + assert factory.get_channel(element="DIST", interval="minute") == "UDT" + assert factory.get_channel(element="DST", interval="minute") == "UGD" + assert factory.get_channel(element="U_Dist", interval="minute") == "UFU" + + # test legacy format + factory = SNCLFactory(data_format="legacy") + assert factory.get_channel(element="D", interval="minute") == "MVD" + assert factory.get_channel(element="F", interval="minute") == "MSF" + assert factory.get_channel(element="H", interval="minute") == "MVH" + assert factory.get_channel(element="Dst4", interval="minute") == "MX4" + assert factory.get_channel(element="Dst3", interval="minute") == "MX3" + assert factory.get_channel(element="E-E", interval="minute") == "MQE" + assert factory.get_channel(element="E-N", interval="minute") == "MQN" + assert factory.get_channel(element="SQ", interval="minute") == "MSQ" + assert factory.get_channel(element="SV", interval="minute") == "MSV" + assert factory.get_channel(element="DIST", interval="minute") == "MDT" + assert factory.get_channel(element="DST", interval="minute") == "MGD" + assert factory.get_channel(element="H_Dist", interval="minute") == "MVH" + + +def test_get_location(): + factory = SNCLFactory(data_format="miniseed") + assert factory.get_location(element="D", data_type="variation") == "R0" + assert factory.get_location(element="D", data_type="adjusted") == "A0" + assert factory.get_location(element="D", data_type="quasi-definitive") == "Q0" + assert factory.get_location(element="D", data_type="definitive") == "D0" + assert factory.get_location(element="D_Sat", data_type="variation") == "R1" + assert factory.get_location(element="D_Dist", data_type="variation") == "RD" + assert factory.get_location(element="D_SQ", data_type="variation") == "RQ" + assert factory.get_location(element="D_SV", data_type="variation") == "RV" diff --git a/test/edge_test/SNCL_test.py b/test/edge_test/SNCL_test.py new file mode 100644 index 000000000..7f59107d9 --- /dev/null +++ b/test/edge_test/SNCL_test.py @@ -0,0 +1,328 @@ +from geomagio.edge import SNCL + + +def test_data_type(): + assert SNCL(station="BOU", channel="LFU", location="R0").data_type == "variation" + assert SNCL(station="BOU", channel="LFU", location="A0").data_type == "adjusted" + assert ( + SNCL(station="BOU", channel="LFU", location="Q0").data_type + == "quasi-definitive" + ) + assert SNCL(station="BOU", channel="LFU", location="D0").data_type == "definitive" + + +def test_interval(): + # miniseed format + assert ( + SNCL( + station="BOU", + channel="BEU", + location="R0", + ).interval + == "tenhertz" + ) + assert ( + SNCL( + station="BOU", + channel="LEU", + location="R0", + ).interval + == "second" + ) + assert ( + SNCL( + station="BOU", + channel="UEU", + location="R0", + ).interval + == "minute" + ) + assert ( + SNCL( + station="BOU", + channel="REU", + location="R0", + ).interval + == "hour" + ) + assert ( + SNCL( + station="BOU", + channel="PEU", + location="R0", + ).interval + == "day" + ) + # legacy format + assert ( + SNCL( + station="BOU", + channel="SVH", + location="R0", + data_format="legacy", + ).interval + == "second" + ) + assert ( + SNCL( + station="BOU", + channel="MVH", + location="R0", + data_format="legacy", + ).interval + == "minute" + ) + assert ( + SNCL( + station="BOU", + channel="HVH", + location="R0", + data_format="legacy", + ).interval + == "hour" + ) + assert ( + SNCL( + station="BOU", + channel="DVH", + location="R0", + data_format="legacy", + ).interval + == "day" + ) + + +def test_element(): + assert ( + SNCL( + station="BOU", + channel="UFD", + location="R0", + ).element + == "D" + ) + assert ( + SNCL( + station="BOU", + channel="UFU", + location="R0", + ).element + == "U" + ) + assert ( + SNCL( + station="BOU", + channel="UFF", + location="R0", + ).element + == "F" + ) + assert ( + SNCL( + station="BOU", + channel="UFH", + location="R0", + ).element + == "H" + ) + assert ( + SNCL( + station="BOU", + channel="UX4", + location="R0", + ).element + == "Dst4" + ) + assert ( + SNCL( + station="BOU", + channel="UX3", + location="R0", + ).element + == "Dst3" + ) + assert ( + SNCL( + station="BOU", + channel="UQE", + location="R0", + ).element + == "E-E" + ) + assert ( + SNCL( + station="BOU", + channel="UQN", + location="R0", + ).element + == "E-N" + ) + assert ( + SNCL( + station="BOU", + channel="BEU", + location="R0", + ).element + == "U_Volt" + ) + assert ( + SNCL( + station="BOU", + channel="BYU", + location="R0", + ).element + == "U_Bin" + ) + assert ( + SNCL( + station="BOU", + channel="UFU", + location="R1", + ).element + == "U_Sat" + ) + + assert ( + SNCL( + station="BOU", + channel="MVD", + location="R0", + data_format="legacy", + ).element + == "D" + ) + assert ( + SNCL( + station="BOU", + channel="MVU", + location="R0", + data_format="legacy", + ).element + == "U" + ) + assert ( + SNCL( + station="BOU", + channel="MSF", + location="R0", + data_format="legacy", + ).element + == "F" + ) + assert ( + SNCL( + station="BOU", + channel="MVH", + location="R0", + data_format="legacy", + ).element + == "H" + ) + assert ( + SNCL( + station="BOU", + channel="MX4", + location="R0", + data_format="legacy", + ).element + == "Dst4" + ) + assert ( + SNCL( + station="BOU", + channel="MX3", + location="R0", + data_format="legacy", + ).element + == "Dst3" + ) + assert ( + SNCL( + station="BOU", + channel="MQE", + location="R0", + data_format="legacy", + ).element + == "E-E" + ) + assert ( + SNCL( + station="BOU", + channel="MQN", + location="R0", + data_format="legacy", + ).element + == "E-N" + ) + assert ( + SNCL( + station="BOU", + channel="MEH", + location="R0", + data_format="legacy", + ).element + == "H_Volt" + ) + assert ( + SNCL( + station="BOU", + channel="MYH", + location="R0", + data_format="legacy", + ).element + == "H_Bin" + ) + assert ( + SNCL( + station="BOU", + channel="MVH", + location="R1", + data_format="legacy", + ).element + == "H_Sat" + ) + assert ( + SNCL( + station="BOU", + channel="MVH", + location="RD", + data_format="legacy", + ).element + == "H_Dist" + ) + assert ( + SNCL( + station="BOU", + channel="MVH", + location="RQ", + data_format="legacy", + ).element + == "H_SQ" + ) + assert ( + SNCL( + station="BOU", + channel="MVH", + location="RV", + data_format="legacy", + ).element + == "H_SV" + ) + assert ( + SNCL( + station="BOU", + channel="MDT", + location="RV", + data_format="legacy", + ).element + == "DIST" + ) + assert ( + SNCL( + station="BOU", + channel="MGD", + location="RV", + data_format="legacy", + ).element + == "DST" + ) -- GitLab From a2f7aed49b4960dbaed6509c7e14bb31a25e8236 Mon Sep 17 00:00:00 2001 From: pcain-usgs <pcain@usgs.gov> Date: Thu, 13 May 2021 17:43:34 -0600 Subject: [PATCH 2/7] implement parse sncl method --- geomagio/edge/SNCL.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/geomagio/edge/SNCL.py b/geomagio/edge/SNCL.py index 20a0a885f..9e9e92b55 100644 --- a/geomagio/edge/SNCL.py +++ b/geomagio/edge/SNCL.py @@ -42,6 +42,15 @@ class SNCL(BaseModel): location: str data_format: str = "miniseed" + def parse_sncl(self) -> Dict: + return { + "station": self.station, + "network": self.network, + "data_type": self.data_type, + "element": self.element, + "interval": self.interval, + } + def dict(self, exclude: Set = {"data_format"}) -> dict: return super().dict( exclude=exclude, -- GitLab From 89022f8bf6e4b887de909aefeea6a0d9117815be Mon Sep 17 00:00:00 2001 From: pcain-usgs <pcain@usgs.gov> Date: Thu, 13 May 2021 17:56:27 -0600 Subject: [PATCH 3/7] implement SNCLFactory in edge/miniseed factories --- geomagio/edge/EdgeFactory.py | 36 +++++++++++------ geomagio/edge/MiniSeedFactory.py | 31 +++++++------- test/edge_test/EdgeFactory_test.py | 56 -------------------------- test/edge_test/MiniSeedFactory_test.py | 50 +---------------------- 4 files changed, 39 insertions(+), 134 deletions(-) diff --git a/geomagio/edge/EdgeFactory.py b/geomagio/edge/EdgeFactory.py index e0f1091c5..bed9e5ec8 100644 --- a/geomagio/edge/EdgeFactory.py +++ b/geomagio/edge/EdgeFactory.py @@ -22,6 +22,7 @@ from ..TimeseriesFactory import TimeseriesFactory from ..TimeseriesFactoryException import TimeseriesFactoryException from ..ObservatoryMetadata import ObservatoryMetadata from .RawInputClient import RawInputClient +from .SNCLFactory import SNCLFactory class EdgeFactory(TimeseriesFactory): @@ -482,13 +483,17 @@ class EdgeFactory(TimeseriesFactory): obspy.core.trace timeseries trace of the requested channel data """ - station = self._get_edge_station(observatory, channel, type, interval) - location = self._get_edge_location(observatory, channel, type, interval) - network = self._get_edge_network(observatory, channel, type, interval) - edge_channel = self._get_edge_channel(observatory, channel, type, interval) + sncl = SNCLFactory(data_format="legacy").get_sncl( + station=observatory, data_type=type, element=channel, interval=interval + ) try: data = self.client.get_waveforms( - network, station, location, edge_channel, starttime, endtime + sncl.network, + sncl.station, + sncl.location, + sncl.channel, + starttime, + endtime, ) except TypeError: # get_waveforms() fails if no data is returned from Edge @@ -506,9 +511,9 @@ class EdgeFactory(TimeseriesFactory): channel, type, interval, - network, - station, - location, + sncl.network, + sncl.station, + sncl.location, ) self._set_metadata(data, observatory, channel, type, interval) return data @@ -576,10 +581,9 @@ class EdgeFactory(TimeseriesFactory): ----- RawInputClient seems to only work when sockets are """ - station = self._get_edge_station(observatory, channel, type, interval) - location = self._get_edge_location(observatory, channel, type, interval) - network = self._get_edge_network(observatory, channel, type, interval) - edge_channel = self._get_edge_channel(observatory, channel, type, interval) + sncl = SNCLFactory(data_format="legacy").get_sncl( + station=observatory, data_type=type, element=channel, interval=interval + ) now = obspy.core.UTCDateTime(datetime.utcnow()) if ((now - endtime) > 864000) and (self.cwbport > 0): @@ -590,7 +594,13 @@ class EdgeFactory(TimeseriesFactory): port = self.write_port ric = RawInputClient( - self.tag, host, port, station, edge_channel, location, network + self.tag, + host, + port, + sncl.station, + sncl.channel, + sncl.location, + sncl.network, ) stream = self._convert_stream_to_masked(timeseries=timeseries, channel=channel) diff --git a/geomagio/edge/MiniSeedFactory.py b/geomagio/edge/MiniSeedFactory.py index 99c3b9eec..211ccf349 100644 --- a/geomagio/edge/MiniSeedFactory.py +++ b/geomagio/edge/MiniSeedFactory.py @@ -23,6 +23,7 @@ from ..TimeseriesFactory import TimeseriesFactory from ..TimeseriesFactoryException import TimeseriesFactoryException from ..ObservatoryMetadata import ObservatoryMetadata from .MiniSeedInputClient import MiniSeedInputClient +from .SNCLFactory import SNCLFactory class MiniSeedFactory(TimeseriesFactory): @@ -524,12 +525,11 @@ class MiniSeedFactory(TimeseriesFactory): obspy.core.trace timeseries trace of the requested channel data """ - station = self._get_edge_station(observatory, channel, type, interval) - location = self._get_edge_location(observatory, channel, type, interval) - network = self._get_edge_network(observatory, channel, type, interval) - edge_channel = self._get_edge_channel(observatory, channel, type, interval) + sncl = SNCLFactory().get_sncl( + station=observatory, data_type=type, element=channel, interval=interval + ) data = self.client.get_waveforms( - network, station, location, edge_channel, starttime, endtime + sncl.network, sncl.station, sncl.location, sncl.channel, starttime, endtime ) data.merge() if data.count() == 0: @@ -540,9 +540,9 @@ class MiniSeedFactory(TimeseriesFactory): channel, type, interval, - network, - station, - location, + sncl.network, + sncl.station, + sncl.location, ) self._set_metadata(data, observatory, channel, type, interval) return data @@ -666,15 +666,14 @@ class MiniSeedFactory(TimeseriesFactory): to_write = to_write.split() to_write = TimeseriesUtility.unmask_stream(to_write) # relabel channels from internal to edge conventions - station = self._get_edge_station(observatory, channel, type, interval) - location = self._get_edge_location(observatory, channel, type, interval) - network = self._get_edge_network(observatory, channel, type, interval) - edge_channel = self._get_edge_channel(observatory, channel, type, interval) + sncl = SNCLFactory().get_sncl( + station=observatory, data_type=type, element=channel, interval=interval + ) for trace in to_write: - trace.stats.station = station - trace.stats.location = location - trace.stats.network = network - trace.stats.channel = edge_channel + trace.stats.station = sncl.station + trace.stats.location = sncl.location + trace.stats.network = sncl.network + trace.stats.channel = sncl.channel # finally, send to edge self.write_client.send(to_write) diff --git a/test/edge_test/EdgeFactory_test.py b/test/edge_test/EdgeFactory_test.py index fca38a8c8..6b524fb31 100644 --- a/test/edge_test/EdgeFactory_test.py +++ b/test/edge_test/EdgeFactory_test.py @@ -5,62 +5,6 @@ from geomagio.edge import EdgeFactory from numpy.testing import assert_equal -def test__get_edge_network(): - """edge_test.EdgeFactory_test.test__get_edge_network()""" - # _get_edge_network should always return NT for use by USGS geomag - assert_equal(EdgeFactory()._get_edge_network(" ", " ", " ", " "), "NT") - - -def test__get_edge_station(): - """edge_test.EdgeFactory_test.test__get_edge_station()""" - # _get_edge_station will return the observatory code passed in. - assert_equal(EdgeFactory()._get_edge_station("BOU", " ", " ", " "), "BOU") - - -def test__get_edge_channel(): - """edge_test.EdgeFactory_test.test__get_edge_channel()""" - # Call private function _get_edge_channel, make certain - # it gets back the appropriate 2 character code. - assert_equal(EdgeFactory()._get_edge_channel("", "D", "", "minute"), "MVD") - assert_equal(EdgeFactory()._get_edge_channel("", "E", "", "minute"), "MVE") - assert_equal(EdgeFactory()._get_edge_channel("", "F", "", "minute"), "MSF") - assert_equal(EdgeFactory()._get_edge_channel("", "H", "", "minute"), "MVH") - assert_equal(EdgeFactory()._get_edge_channel("", "DIST", "", "minute"), "MDT") - assert_equal(EdgeFactory()._get_edge_channel("", "DST", "", "minute"), "MGD") - assert_equal(EdgeFactory()._get_edge_channel("", "E-E", "", "minute"), "MQE") - assert_equal(EdgeFactory()._get_edge_channel("", "E-N", "", "minute"), "MQN") - - -def test__get_edge_location(): - """edge_test.EdgeFactory_test.test__get_edge_location()""" - # Call _get_edge_location, make certain it returns the correct edge - # location code. - assert_equal(EdgeFactory()._get_edge_location("", "", "variation", ""), "R0") - assert_equal(EdgeFactory()._get_edge_location("", "", "quasi-definitive", ""), "Q0") - assert_equal(EdgeFactory()._get_edge_location("", "", "definitive", ""), "D0") - - -def test__get_interval_code(): - """edge_test.EdgeFactory_test.test__get_interval_code()""" - assert_equal(EdgeFactory()._get_interval_code("day"), "D") - assert_equal(EdgeFactory()._get_interval_code("hour"), "H") - assert_equal(EdgeFactory()._get_interval_code("minute"), "M") - assert_equal(EdgeFactory()._get_interval_code("second"), "S") - - -def test__set_metadata(): - """edge_test.EdgeFactory_test.test__set_metadata()""" - # Call _set_metadata with 2 traces, and make certain the stats get - # set for both traces. - trace1 = Trace() - trace2 = Trace() - stream = Stream(traces=[trace1, trace2]) - EdgeFactory()._set_metadata(stream, "BOU", "H", "variation", "minute") - assert_equal(stream[0].stats["channel"], "H") - assert_equal(stream[1].stats["channel"], "H") - - -# def test_get_timeseries(): def dont_get_timeseries(): """edge_test.EdgeFactory_test.test_get_timeseries()""" # Call get_timeseries, and test stats for comfirmation that it came back. diff --git a/test/edge_test/MiniSeedFactory_test.py b/test/edge_test/MiniSeedFactory_test.py index a0c57869e..bd1367d37 100644 --- a/test/edge_test/MiniSeedFactory_test.py +++ b/test/edge_test/MiniSeedFactory_test.py @@ -9,54 +9,6 @@ from geomagio import TimeseriesUtility from geomagio.edge import MiniSeedFactory, MiniSeedInputClient -def test__get_edge_network(): - """edge_test.MiniSeedFactory_test.test__get_edge_network()""" - # _get_edge_network should always return NT for use by USGS geomag - assert_equal(MiniSeedFactory()._get_edge_network(" ", " ", " ", " "), "NT") - - -def test__get_edge_station(): - """edge_test.MiniSeedFactory_test.test__get_edge_station()""" - # _get_edge_station will return the observatory code passed in. - assert_equal(MiniSeedFactory()._get_edge_station("BOU", " ", " ", " "), "BOU") - - -def test__get_edge_channel(): - """edge_test.MiniSeedFactory_test.test__get_edge_channel()""" - # Call private function _get_edge_channel, make certain - # it gets back the appropriate 2 character code. - factory = MiniSeedFactory() - assert_equal(factory._get_edge_channel("", "D", "", "minute"), "UFD") - assert_equal(factory._get_edge_channel("", "U", "", "minute"), "UFU") - assert_equal(factory._get_edge_channel("", "F", "", "minute"), "UFF") - assert_equal(factory._get_edge_channel("", "H", "", "minute"), "UFH") - assert_equal(factory._get_edge_channel("", "BEU", "", "minute"), "BEU") - assert_equal(factory._get_edge_channel("", "Dst4", "", "minute"), "UX4") - assert_equal(factory._get_edge_channel("", "Dst3", "", "minute"), "UX3") - assert_equal(factory._get_edge_channel("", "E-E", "", "minute"), "UQE") - assert_equal(factory._get_edge_channel("", "E-N", "", "minute"), "UQN") - - -def test__get_edge_location(): - """edge_test.MiniSeedFactory_test.test__get_edge_location()""" - # Call _get_edge_location, make certain it returns the correct edge - # location code. - assert_equal(MiniSeedFactory()._get_edge_location("", "", "variation", ""), "R0") - assert_equal( - MiniSeedFactory()._get_edge_location("", "", "quasi-definitive", ""), "Q0" - ) - assert_equal(MiniSeedFactory()._get_edge_location("", "", "definitive", ""), "D0") - - -def test__get_interval_code(): - """edge_test.MiniSeedFactory_test.test__get_interval_code()""" - assert_equal(MiniSeedFactory()._get_interval_code("day"), "P") - assert_equal(MiniSeedFactory()._get_interval_code("hour"), "R") - assert_equal(MiniSeedFactory()._get_interval_code("minute"), "U") - assert_equal(MiniSeedFactory()._get_interval_code("second"), "L") - assert_equal(MiniSeedFactory()._get_interval_code("tenhertz"), "B") - - class MockMiniSeedInputClient(object): def __init__(self): self.close_called = False @@ -167,7 +119,7 @@ def __create_trace( channel="H", location="R0", data_interval="second", - data_type="interval", + data_type="variation", ): """ Utility to create a trace containing the given numpy array. -- GitLab From 39b9512b3c7a82140fefb5cae9cd99ce0dc3aceb Mon Sep 17 00:00:00 2001 From: pcain-usgs <pcain@usgs.gov> Date: Fri, 14 May 2021 07:29:34 -0600 Subject: [PATCH 4/7] Remove old sncl methods from factories, fix interval code for predefined channels, support chan.loc format --- geomagio/edge/EdgeFactory.py | 182 ------------------------- geomagio/edge/MiniSeedFactory.py | 206 ----------------------------- geomagio/edge/SNCL.py | 11 +- geomagio/edge/SNCLFactory.py | 27 ++-- test/edge_test/SNCLFactory_test.py | 10 ++ 5 files changed, 36 insertions(+), 400 deletions(-) diff --git a/geomagio/edge/EdgeFactory.py b/geomagio/edge/EdgeFactory.py index bed9e5ec8..a4294c79b 100644 --- a/geomagio/edge/EdgeFactory.py +++ b/geomagio/edge/EdgeFactory.py @@ -278,188 +278,6 @@ class EdgeFactory(TimeseriesFactory): trace.data = numpy.ma.masked_invalid(trace.data) return stream - def _get_edge_channel(self, observatory, channel, type, interval): - """get edge channel. - - Parameters - ---------- - observatory : str - observatory code - channel : str - single character channel {H, E, D, Z, F, X, Y, G} or - any appropriate edge channel, ie MSD, MGD, HGD. - type : str - data type {definitive, quasi-definitive, variation} - interval : str - interval length {minute, second} - - Returns - ------- - edge_channel - {MVH, MVE, MVD, MGD etc} - """ - edge_interval_code = self._get_interval_code(interval) - edge_channel = None - - # If form is chan.loc, return chan (left) portion. - # Allows specific chan/loc selection. - if channel.find(".") >= 0: - tmplist = channel.split(".") - return tmplist[0].strip() - - if channel == "D": - edge_channel = edge_interval_code + "VD" - elif channel == "E": - edge_channel = edge_interval_code + "VE" - elif channel == "F": - edge_channel = edge_interval_code + "SF" - elif channel == "H": - edge_channel = edge_interval_code + "VH" - elif channel == "Z": - edge_channel = edge_interval_code + "VZ" - elif channel == "G": - edge_channel = edge_interval_code + "SG" - elif channel == "X": - edge_channel = edge_interval_code + "VX" - elif channel == "Y": - edge_channel = edge_interval_code + "VY" - elif channel == "E-E": - edge_channel = edge_interval_code + "QE" - elif channel == "E-N": - edge_channel = edge_interval_code + "QN" - elif channel == "DIST": - edge_channel = edge_interval_code + "DT" - elif channel == "DST": - edge_channel = edge_interval_code + "GD" - elif channel == "SQ": - edge_channel = edge_interval_code + "SQ" - elif channel == "SV": - edge_channel = edge_interval_code + "SV" - else: - edge_channel = channel - return edge_channel - - def _get_edge_location(self, observatory, channel, type, interval): - """get edge location. - - The edge location code is currently determined by the type - passed in. - - Parameters - ---------- - observatory : str - observatory code - channel : str - single character channel {H, E, D, Z, F} - type : str - data type {definitive, quasi-definitive, variation} - interval : str - interval length {minute, second} - - Returns - ------- - location - returns an edge location code - """ - location = None - - # If form is chan.loc, return loc (right) portion - # Allows specific chan/loc selection. - if channel.find(".") >= 0: - tmplist = channel.split(".") - return tmplist[1].strip() - - if self.locationCode is not None: - location = self.locationCode - else: - if type == "variation" or type == "reported": - location = "R0" - elif type == "adjusted" or type == "provisional": - location = "A0" - elif type == "quasi-definitive": - location = "Q0" - elif type == "definitive": - location = "D0" - elif len(type) == 2: - location = type - return location - - def _get_edge_network(self, observatory, channel, type, interval): - """get edge network code. - - Parameters - ---------- - observatory : str - observatory code - channel : str - single character channel {H, E, D, Z, F} - type : str - data type {definitive, quasi-definitive, variation} - interval : str - interval length {minute, second} - - Returns - ------- - network - always NT - """ - return "NT" - - def _get_edge_station(self, observatory, channel, type, interval): - """get edge station. - - Parameters - ---------- - observatory : str - observatory code - channel : str - single character channel {H, E, D, Z, F} - type : str - data type {definitive, quasi-definitive, variation} - interval : str - interval length {minute, second} - - Returns - ------- - station - the observatory is returned as the station - """ - return observatory - - def _get_interval_code(self, interval): - """get edge interval code. - - Converts the metadata interval string, into an edge single character - edge code. - - Parameters - ---------- - observatory : str - observatory code - channel : str - single character channel {H, E, D, Z, F} - type : str - data type {definitive, quasi-definitive, variation} - interval : str - interval length {minute, second} - - Returns - ------- - interval type - """ - interval_code = None - if interval == "day": - interval_code = "D" - elif interval == "hour": - interval_code = "H" - elif interval == "minute": - interval_code = "M" - elif interval == "second": - interval_code = "S" - else: - raise TimeseriesFactoryException('Unexpected interval "%s"' % interval) - return interval_code - def _get_timeseries(self, starttime, endtime, observatory, channel, type, interval): """get timeseries data for a single channel. diff --git a/geomagio/edge/MiniSeedFactory.py b/geomagio/edge/MiniSeedFactory.py index 211ccf349..133edeeae 100644 --- a/geomagio/edge/MiniSeedFactory.py +++ b/geomagio/edge/MiniSeedFactory.py @@ -296,212 +296,6 @@ class MiniSeedFactory(TimeseriesFactory): trace.data = numpy.ma.masked_invalid(trace.data) return stream - def _get_edge_channel(self, observatory, channel, type, interval): - """get edge channel. - - Parameters - ---------- - observatory : str - observatory code - channel : str - single character channel {H, E, D, Z, F, X, Y, G} or - any appropriate edge channel, ie MSD, MGD, HGD. - type : str - data type {definitive, quasi-definitive, variation} - interval : str - interval length {'day', 'hour', 'minute', 'second', 'tenhertz'} - - Returns - ------- - edge_channel - {MVH, MVE, MVD, MGD etc} - """ - edge_interval_code = self._get_interval_code(interval) - edge_channel = None - - # If form is chan.loc, return chan (left) portion. - # Allows specific chan/loc selection. - if channel.find(".") >= 0: - tmplist = channel.split(".") - return tmplist[0].strip() - - # see if channel name uses _ for ELEMENT_SUFFIX - element = None - suffix = None - if channel.find("_") >= 0: - element, suffix = channel.split("_") - - # 10Hz should be bin/volt - if interval == "tenhertz": - middle = None - if suffix == "Bin": - middle = "Y" - elif suffix == "Volt": - middle = "E" - elif suffix is not None: - raise TimeseriesFactoryException( - 'bad channel suffix "%s", wanted "Bin" or "Volt"' % suffix - ) - # check for expected channels - if element in ("U", "V", "W") and middle is not None: - return edge_interval_code + middle + element - else: - # unknown, assume advanced user - return channel - - if suffix is not None: - if suffix == "Dist" or suffix == "SQ" or suffix == "SV" or suffix == "DT": - # these suffixes modify location code, but use element channel - channel = element - else: - raise TimeseriesFactoryException( - 'bad channel suffix "%s", wanted "Dist", "SQ", or "SV"' % suffix - ) - if channel in ("D", "F", "G", "H", "U", "V", "W", "X", "Y", "Z"): - # normal elements - edge_channel = edge_interval_code + "F" + channel - elif channel == "E-E": - edge_channel = edge_interval_code + "QE" - elif channel == "E-N": - edge_channel = edge_interval_code + "QN" - elif channel == "Dst4": - edge_channel = edge_interval_code + "X4" - elif channel == "Dst3": - edge_channel = edge_interval_code + "X3" - else: - edge_channel = channel - return edge_channel - - def _get_edge_location(self, observatory, channel, data_type, interval): - """get edge location. - - The edge location code is currently determined by the type - passed in. - - Parameters - ---------- - observatory : str - observatory code - channel : str - single character channel {H, E, D, Z, F} - data_type : str - data type {definitive, quasi-definitive, variation} - interval : str - interval length {'day', 'hour', 'minute', 'second', 'tenhertz'} - - Returns - ------- - location - returns an edge location code - """ - # If form is chan.loc, return loc (right) portion - # Allows specific chan/loc selection. - if channel.find(".") >= 0: - tmplist = channel.split(".") - return tmplist[1].strip() - # factory override - if self.locationCode is not None: - return self.locationCode - # determine prefix - location_prefix = "R" - if data_type == "variation" or data_type == "reported": - location_prefix = "R" - elif data_type == "adjusted" or data_type == "provisional": - location_prefix = "A" - elif data_type == "quasi-definitive": - location_prefix = "Q" - elif data_type == "definitive": - location_prefix = "D" - # determine suffix - location_suffix = "0" - if channel.find("_") >= 0: - _, suffix = channel.split("_") - if suffix == "Dist": - location_suffix = "D" - elif suffix == "SQ": - location_suffix = "Q" - elif suffix == "SV": - location_suffix = "V" - elif suffix == "DT": - location_suffix = "R" - elif suffix not in ("Bin", "Volt"): - raise TimeseriesFactoryException( - 'bad channel suffix "%s", wanted "Dist", "SQ", or "SV"' % suffix - ) - return location_prefix + location_suffix - - def _get_edge_network(self, observatory, channel, type, interval): - """get edge network code. - - Parameters - ---------- - observatory : str - observatory code - channel : str - single character channel {H, E, D, Z, F} - type : str - data type {definitive, quasi-definitive, variation} - interval : str - interval length {'day', 'hour', 'minute', 'second', 'tenhertz'} - - Returns - ------- - network - always NT - """ - return "NT" - - def _get_edge_station(self, observatory, channel, type, interval): - """get edge station. - - Parameters - ---------- - observatory : str - observatory code - channel : str - single character channel {H, E, D, Z, F} - type : str - data type {definitive, quasi-definitive, variation} - interval : str - interval length {'day', 'hour', 'minute', 'second', 'tenhertz'} - - Returns - ------- - station - the observatory is returned as the station - """ - return observatory - - def _get_interval_code(self, interval): - """get edge interval code. - - Converts the metadata interval string, into an edge single character - edge code. - - Parameters - ---------- - interval : str - interval length {'day', 'hour', 'minute', 'second', 'tenhertz'} - - Returns - ------- - interval type - """ - interval_code = None - if interval == "day": - interval_code = "P" - elif interval == "hour": - interval_code = "R" - elif interval == "minute": - interval_code = "U" - elif interval == "second": - interval_code = "L" - elif interval == "tenhertz": - interval_code = "B" - else: - raise TimeseriesFactoryException('Unexpected interval "%s"' % interval) - return interval_code - def _get_timeseries(self, starttime, endtime, observatory, channel, type, interval): """get timeseries data for a single channel. diff --git a/geomagio/edge/SNCL.py b/geomagio/edge/SNCL.py index 9e9e92b55..df75fa3a4 100644 --- a/geomagio/edge/SNCL.py +++ b/geomagio/edge/SNCL.py @@ -63,6 +63,7 @@ class SNCL(BaseModel): @property def data_type(self) -> str: + """Translates beginning of location code to data type""" location_start = self.location[0] if location_start == "R": return "variation" @@ -76,12 +77,13 @@ class SNCL(BaseModel): @property def element(self) -> str: - element = self.__get_predefined_element() - element = element or self.__get_element() - return element + predefined_element = self.__check_predefined_element() + element = self.__get_element() + return predefined_element or element @property def interval(self) -> str: + """Translates beginning of channel to interval""" interval_conversions = INTERVAL_CONVERSIONS[self.data_format] interval_code_conversions = { interval_conversions[key]: key for key in interval_conversions.keys() @@ -93,6 +95,7 @@ class SNCL(BaseModel): raise ValueError(f"Unexcepted interval code: {channel_start}") def __get_element(self): + """Translates channel/location to element""" element_start = self.channel[2] channel = self.channel channel_middle = channel[1] @@ -115,7 +118,7 @@ class SNCL(BaseModel): element_end = "" return element_start + element_end - def __get_predefined_element(self) -> Optional[str]: + def __check_predefined_element(self) -> Optional[str]: channel = self.channel channel_end = channel[1:] if channel_end in CHANNEL_CONVERSIONS: diff --git a/geomagio/edge/SNCLFactory.py b/geomagio/edge/SNCLFactory.py index 4e677c0af..4b76fa157 100644 --- a/geomagio/edge/SNCLFactory.py +++ b/geomagio/edge/SNCLFactory.py @@ -23,10 +23,12 @@ class SNCLFactory(object): ) def get_channel(self, element: str, interval: str) -> str: + predefined_channel = self.__check_predefined_channel( + element=element, interval=interval + ) channel_start = self.__get_channel_start(interval=interval) - channel_end = self.__get_predefined_channel(element=element) - channel_end = channel_end or self.__get_channel_end(element=element) - return channel_start + channel_end + channel_end = self.__get_channel_end(element=element) + return predefined_channel or (channel_start + channel_end) def get_location(self, element: str, data_type: str) -> str: location_start = self.__get_location_start(data_type=data_type) @@ -39,11 +41,18 @@ class SNCLFactory(object): except: raise ValueError(f"Unexpected interval: {interval}") - def __get_predefined_channel(self, element: str) -> Optional[str]: - if len(element) == 3 and "-" not in element and element != "DST": - return element[1:] - elif element in ELEMENT_CONVERSIONS: - return ELEMENT_CONVERSIONS[element] + def __check_predefined_channel(self, element: str, interval: str) -> Optional[str]: + if element in ELEMENT_CONVERSIONS: + return ( + self.__get_channel_start(interval=interval) + + ELEMENT_CONVERSIONS[element] + ) + elif len(element) == 3: + return element + # chan.loc format + elif "." in element: + channel = element.split(".")[0] + return channel.strip() else: return None @@ -61,6 +70,7 @@ class SNCLFactory(object): return channel_middle + channel_end def __get_location_start(self, data_type: str) -> str: + """Translates data type to beginning of location code""" if data_type == "variation": return "R" elif data_type == "adjusted": @@ -72,6 +82,7 @@ class SNCLFactory(object): raise ValueError(f"Unexpected data type: {data_type}") def __get_location_end(self, element: str) -> str: + """Translates element suffix to end of location code""" if "_Sat" in element: return "1" if "_Dist" in element: diff --git a/test/edge_test/SNCLFactory_test.py b/test/edge_test/SNCLFactory_test.py index d12ab5f47..44f2d0de0 100644 --- a/test/edge_test/SNCLFactory_test.py +++ b/test/edge_test/SNCLFactory_test.py @@ -34,9 +34,14 @@ def test_get_channel(): assert factory.get_channel(element="E-N", interval="minute") == "UQN" assert factory.get_channel(element="SQ", interval="minute") == "USQ" assert factory.get_channel(element="SV", interval="minute") == "USV" + assert factory.get_channel(element="UK1", interval="minute") == "UK1" + assert factory.get_channel(element="UK2", interval="minute") == "UK2" + assert factory.get_channel(element="UK3", interval="minute") == "UK3" + assert factory.get_channel(element="UK4", interval="minute") == "UK4" assert factory.get_channel(element="DIST", interval="minute") == "UDT" assert factory.get_channel(element="DST", interval="minute") == "UGD" assert factory.get_channel(element="U_Dist", interval="minute") == "UFU" + assert factory.get_channel(element="UK1.R0", interval="minute") == "UK1" # test legacy format factory = SNCLFactory(data_format="legacy") @@ -49,9 +54,14 @@ def test_get_channel(): assert factory.get_channel(element="E-N", interval="minute") == "MQN" assert factory.get_channel(element="SQ", interval="minute") == "MSQ" assert factory.get_channel(element="SV", interval="minute") == "MSV" + assert factory.get_channel(element="UK1", interval="minute") == "UK1" + assert factory.get_channel(element="UK2", interval="minute") == "UK2" + assert factory.get_channel(element="UK3", interval="minute") == "UK3" + assert factory.get_channel(element="UK4", interval="minute") == "UK4" assert factory.get_channel(element="DIST", interval="minute") == "MDT" assert factory.get_channel(element="DST", interval="minute") == "MGD" assert factory.get_channel(element="H_Dist", interval="minute") == "MVH" + assert factory.get_channel(element="UK1.R0", interval="minute") == "UK1" def test_get_location(): -- GitLab From c307eb7ca63a59bf6c06705da0fdadb36b6b22b0 Mon Sep 17 00:00:00 2001 From: pcain-usgs <pcain@usgs.gov> Date: Mon, 17 May 2021 15:33:37 -0600 Subject: [PATCH 5/7] separate sncl models --- geomagio/edge/EdgeFactory.py | 13 +- geomagio/edge/LegacySNCL.py | 81 ++++++++++ geomagio/edge/MiniSeedFactory.py | 13 +- geomagio/edge/SNCL.py | 77 +++++----- geomagio/edge/SNCLFactory.py | 73 ++++++--- geomagio/edge/__init__.py | 2 + test/edge_test/LegacySNCL_test.py | 169 ++++++++++++++++++++ test/edge_test/SNCLFactory_test.py | 72 ++++----- test/edge_test/SNCL_test.py | 238 +++++------------------------ 9 files changed, 421 insertions(+), 317 deletions(-) create mode 100644 geomagio/edge/LegacySNCL.py create mode 100644 test/edge_test/LegacySNCL_test.py diff --git a/geomagio/edge/EdgeFactory.py b/geomagio/edge/EdgeFactory.py index a4294c79b..af226a63a 100644 --- a/geomagio/edge/EdgeFactory.py +++ b/geomagio/edge/EdgeFactory.py @@ -22,7 +22,7 @@ from ..TimeseriesFactory import TimeseriesFactory from ..TimeseriesFactoryException import TimeseriesFactoryException from ..ObservatoryMetadata import ObservatoryMetadata from .RawInputClient import RawInputClient -from .SNCLFactory import SNCLFactory +from .LegacySNCL import LegacySNCL class EdgeFactory(TimeseriesFactory): @@ -301,8 +301,11 @@ class EdgeFactory(TimeseriesFactory): obspy.core.trace timeseries trace of the requested channel data """ - sncl = SNCLFactory(data_format="legacy").get_sncl( - station=observatory, data_type=type, element=channel, interval=interval + sncl = LegacySNCL().get_sncl( + station=observatory, + data_type=type, + interval=interval, + element=channel, ) try: data = self.client.get_waveforms( @@ -399,8 +402,8 @@ class EdgeFactory(TimeseriesFactory): ----- RawInputClient seems to only work when sockets are """ - sncl = SNCLFactory(data_format="legacy").get_sncl( - station=observatory, data_type=type, element=channel, interval=interval + sncl = LegacySNCL().get_sncl( + station=observatory, data_type=type, interval=interval, element=channel ) now = obspy.core.UTCDateTime(datetime.utcnow()) diff --git a/geomagio/edge/LegacySNCL.py b/geomagio/edge/LegacySNCL.py new file mode 100644 index 000000000..be1c3300d --- /dev/null +++ b/geomagio/edge/LegacySNCL.py @@ -0,0 +1,81 @@ +from __future__ import annotations +from typing import Optional + +from .SNCL import SNCL + +ELEMENT_CONVERSIONS = { + # e-field + "E-E": "QE", + "E-N": "QN", + # derived indicies + "SQ": "SQ", + "SV": "SV", + "DIST": "DT", + "DST": "GD", +} +CHANNEL_CONVERSIONS = { + ELEMENT_CONVERSIONS[key]: key for key in ELEMENT_CONVERSIONS.keys() +} + + +class LegacySNCL(SNCL): + def get_sncl( + self, + station: str, + data_type: str, + interval: str, + element: str, + ) -> LegacySNCL: + from .SNCLFactory import SNCLFactory + + factory = SNCLFactory(data_format="legacy") + return LegacySNCL( + station=station, + network=self.network, + channel=factory.get_channel(element=element, interval=interval), + location=factory.get_location(element=element, data_type=data_type), + ) + + @property + def element(self) -> str: + predefined_element = self.__check_predefined_element() + element = self.__get_element() + return predefined_element or element + + @property + def interval(self) -> str: + channel_start = self.channel[0] + if channel_start == "S": + return "second" + elif channel_start == "M": + return "minute" + elif channel_start == "H": + return "hour" + elif channel_start == "D": + return "day" + raise ValueError(f"Unexcepted interval code: {channel_start}") + + def __get_element(self): + """Translates channel/location to element""" + element_start = self.channel[2] + channel = self.channel + channel_middle = channel[1] + location_end = self.location[1] + if channel_middle in ["Q", "E"]: + element_end = "_Volt" + elif channel_middle == "Y": + element_end = "_Bin" + elif channel_middle == "K": + element_end = "_Temp" + elif location_end == "1": + element_end = "_Sat" + else: + element_end = "" + return element_start + element_end + + def __check_predefined_element(self) -> Optional[str]: + channel = self.channel + channel_end = channel[1:] + if channel_end in CHANNEL_CONVERSIONS: + return CHANNEL_CONVERSIONS[channel_end] + return None diff --git a/geomagio/edge/MiniSeedFactory.py b/geomagio/edge/MiniSeedFactory.py index 133edeeae..f3530cdd6 100644 --- a/geomagio/edge/MiniSeedFactory.py +++ b/geomagio/edge/MiniSeedFactory.py @@ -23,7 +23,7 @@ from ..TimeseriesFactory import TimeseriesFactory from ..TimeseriesFactoryException import TimeseriesFactoryException from ..ObservatoryMetadata import ObservatoryMetadata from .MiniSeedInputClient import MiniSeedInputClient -from .SNCLFactory import SNCLFactory +from .SNCL import SNCL class MiniSeedFactory(TimeseriesFactory): @@ -319,8 +319,8 @@ class MiniSeedFactory(TimeseriesFactory): obspy.core.trace timeseries trace of the requested channel data """ - sncl = SNCLFactory().get_sncl( - station=observatory, data_type=type, element=channel, interval=interval + sncl = SNCL().get_sncl( + station=observatory, data_type=type, interval=interval, element=channel ) data = self.client.get_waveforms( sncl.network, sncl.station, sncl.location, sncl.channel, starttime, endtime @@ -460,8 +460,11 @@ class MiniSeedFactory(TimeseriesFactory): to_write = to_write.split() to_write = TimeseriesUtility.unmask_stream(to_write) # relabel channels from internal to edge conventions - sncl = SNCLFactory().get_sncl( - station=observatory, data_type=type, element=channel, interval=interval + sncl = SNCL().get_sncl( + station=observatory, + data_type=type, + interval=interval, + element=channel, ) for trace in to_write: trace.stats.station = sncl.station diff --git a/geomagio/edge/SNCL.py b/geomagio/edge/SNCL.py index df75fa3a4..395bfefe5 100644 --- a/geomagio/edge/SNCL.py +++ b/geomagio/edge/SNCL.py @@ -1,22 +1,8 @@ -from typing import Dict, Optional, Set +from __future__ import annotations +from typing import Dict, Optional from pydantic import BaseModel -INTERVAL_CONVERSIONS = { - "legacy": { - "second": "S", - "minute": "M", - "hour": "H", - "day": "D", - }, - "miniseed": { - "tenhertz": "B", - "second": "L", - "minute": "U", - "hour": "R", - "day": "P", - }, -} ELEMENT_CONVERSIONS = { # e-field "E-E": "QE", @@ -24,10 +10,6 @@ ELEMENT_CONVERSIONS = { # derived indicies "Dst3": "X3", "Dst4": "X4", - "SQ": "SQ", - "SV": "SV", - "DIST": "DT", - "DST": "GD", } CHANNEL_CONVERSIONS = { @@ -36,11 +18,27 @@ CHANNEL_CONVERSIONS = { class SNCL(BaseModel): - station: str + station: str = None network: str = "NT" - channel: str - location: str - data_format: str = "miniseed" + channel: str = None + location: str = None + + def get_sncl( + self, + station: str, + data_type: str, + interval: str, + element: str, + ) -> SNCL: + from .SNCLFactory import SNCLFactory + + factory = SNCLFactory(data_format="miniseed") + return SNCL( + station=station, + network=self.network, + channel=factory.get_channel(element=element, interval=interval), + location=factory.get_location(element=element, data_type=data_type), + ) def parse_sncl(self) -> Dict: return { @@ -51,16 +49,6 @@ class SNCL(BaseModel): "interval": self.interval, } - def dict(self, exclude: Set = {"data_format"}) -> dict: - return super().dict( - exclude=exclude, - ) - - def json(self, exclude: Set = {"data_format"}) -> str: - return super().json( - exclude=exclude, - ) - @property def data_type(self) -> str: """Translates beginning of location code to data type""" @@ -84,15 +72,18 @@ class SNCL(BaseModel): @property def interval(self) -> str: """Translates beginning of channel to interval""" - interval_conversions = INTERVAL_CONVERSIONS[self.data_format] - interval_code_conversions = { - interval_conversions[key]: key for key in interval_conversions.keys() - } channel_start = self.channel[0] - try: - return interval_code_conversions[channel_start] - except: - raise ValueError(f"Unexcepted interval code: {channel_start}") + if channel_start == "B": + return "tenhertz" + elif channel_start == "L": + return "second" + elif channel_start == "U": + return "minute" + elif channel_start == "R": + return "hour" + elif channel_start == "P": + return "day" + raise ValueError(f"Unexcepted interval code: {channel_start}") def __get_element(self): """Translates channel/location to element""" @@ -100,7 +91,7 @@ class SNCL(BaseModel): channel = self.channel channel_middle = channel[1] location_end = self.location[1] - if channel_middle in ["Q", "E"]: + if channel_middle == "E": element_end = "_Volt" elif channel_middle == "Y": element_end = "_Bin" diff --git a/geomagio/edge/SNCLFactory.py b/geomagio/edge/SNCLFactory.py index 4b76fa157..c4be5e899 100644 --- a/geomagio/edge/SNCLFactory.py +++ b/geomagio/edge/SNCLFactory.py @@ -1,25 +1,46 @@ -from typing import Optional +from typing import Literal, Optional, Union -from .SNCL import SNCL, INTERVAL_CONVERSIONS, ELEMENT_CONVERSIONS +from .SNCL import SNCL, ELEMENT_CONVERSIONS as MINISEED_CONVERSIONS +from .LegacySNCL import LegacySNCL, ELEMENT_CONVERSIONS as LEGACY_CONVERSIONS + +INTERVAL_CONVERSIONS = { + "miniseed": { + "tenhertz": "B", + "second": "L", + "minute": "U", + "hour": "R", + "day": "P", + }, + "legacy": { + "second": "S", + "minute": "M", + "hour": "H", + "day": "D", + }, +} class SNCLFactory(object): - def __init__(self, data_format: str = "miniseed"): + def __init__(self, data_format: Literal["miniseed", "legacy"] = "miniseed"): self.data_format = data_format def get_sncl( self, station: str, - data_type: str, - element: str, - interval: str, - network: str = "NT", - ) -> SNCL: - return SNCL( - station=station, - network=network, - channel=self.get_channel(element=element, interval=interval), - location=self.get_location(element=element, data_type=data_type), + network: str, + channel: str, + location: str, + ) -> Union[SNCL, LegacySNCL]: + sncl_params = { + "station": station, + "network": network, + "channel": channel, + "location": location, + } + return ( + SNCL(**sncl_params) + if self.data_format == "miniseed" + else LegacySNCL(**sncl_params) ) def get_channel(self, element: str, interval: str) -> str: @@ -36,16 +57,23 @@ class SNCLFactory(object): return location_start + location_end def __get_channel_start(self, interval: str) -> str: + interval_conversions = INTERVAL_CONVERSIONS[self.data_format] try: - return INTERVAL_CONVERSIONS[self.data_format][interval] + return interval_conversions[interval] except: raise ValueError(f"Unexpected interval: {interval}") def __check_predefined_channel(self, element: str, interval: str) -> Optional[str]: - if element in ELEMENT_CONVERSIONS: + channel_conversions = ( + MINISEED_CONVERSIONS + if self.data_format == "miniseed" + else LEGACY_CONVERSIONS + ) + + if element in channel_conversions: return ( self.__get_channel_start(interval=interval) - + ELEMENT_CONVERSIONS[element] + + channel_conversions[element] ) elif len(element) == 3: return element @@ -85,10 +113,11 @@ class SNCLFactory(object): """Translates element suffix to end of location code""" if "_Sat" in element: return "1" - if "_Dist" in element: - return "D" - if "_SQ" in element: - return "Q" - if "_SV" in element: - return "V" + if self.data_format == "miniseed": + if "_Dist" in element: + return "D" + if "_SQ" in element: + return "Q" + if "_SV" in element: + return "V" return "0" diff --git a/geomagio/edge/__init__.py b/geomagio/edge/__init__.py index bf808a25a..77d5fee30 100644 --- a/geomagio/edge/__init__.py +++ b/geomagio/edge/__init__.py @@ -9,6 +9,7 @@ from .MiniSeedInputClient import MiniSeedInputClient from .RawInputClient import RawInputClient from .SNCL import SNCL from .SNCLFactory import SNCLFactory +from .LegacySNCL import LegacySNCL __all__ = [ "EdgeFactory", @@ -20,4 +21,5 @@ __all__ = [ "LegacySNIDE", "SNCL", "SNCLFactory", + "LegacySNCL", ] diff --git a/test/edge_test/LegacySNCL_test.py b/test/edge_test/LegacySNCL_test.py new file mode 100644 index 000000000..8d7233ffc --- /dev/null +++ b/test/edge_test/LegacySNCL_test.py @@ -0,0 +1,169 @@ +from geomagio.edge import LegacySNCL + + +def test_data_type(): + """edge_test.LegacySNCL_test.test_data_type()""" + assert ( + LegacySNCL(station="BOU", channel="LFU", location="R0").data_type == "variation" + ) + assert ( + LegacySNCL(station="BOU", channel="LFU", location="A0").data_type == "adjusted" + ) + assert ( + LegacySNCL(station="BOU", channel="LFU", location="Q0").data_type + == "quasi-definitive" + ) + assert ( + LegacySNCL(station="BOU", channel="LFU", location="D0").data_type + == "definitive" + ) + + +def test_element(): + """edge_test.LegacySNCL_test.test_element()""" + assert ( + LegacySNCL( + station="BOU", + channel="MVD", + location="R0", + ).element + == "D" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MVU", + location="R0", + ).element + == "U" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MSF", + location="R0", + ).element + == "F" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MVH", + location="R0", + ).element + == "H" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MQE", + location="R0", + ).element + == "E-E" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MQN", + location="R0", + ).element + == "E-N" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MEH", + location="R0", + ).element + == "H_Volt" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MYH", + location="R0", + ).element + == "H_Bin" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MVH", + location="R1", + ).element + == "H_Sat" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MDT", + location="R0", + ).element + == "DIST" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MGD", + location="R0", + ).element + == "DST" + ) + + +def test_get_sncl(): + """edge_test.LegacySNCL_test.test_get_sncl()""" + assert LegacySNCL().get_sncl( + station="BOU", data_type="variation", interval="second", element="H" + ) == LegacySNCL(station="BOU", network="NT", channel="SVH", location="R0") + + +def test_interval(): + """edge_test.LegacySNCL_test.test_interval()""" + assert ( + LegacySNCL( + station="BOU", + channel="SVH", + location="R0", + data_format="legacy", + ).interval + == "second" + ) + assert ( + LegacySNCL( + station="BOU", + channel="MVH", + location="R0", + data_format="legacy", + ).interval + == "minute" + ) + assert ( + LegacySNCL( + station="BOU", + channel="HVH", + location="R0", + data_format="legacy", + ).interval + == "hour" + ) + assert ( + LegacySNCL( + station="BOU", + channel="DVH", + location="R0", + data_format="legacy", + ).interval + == "day" + ) + + +def test_parse_sncl(): + """edge_test.LegacySNCL_test.test_parse_sncl()""" + assert LegacySNCL(station="BOU", channel="MVH", location="R0").parse_sncl() == { + "station": "BOU", + "network": "NT", + "data_type": "variation", + "element": "H", + "interval": "minute", + } diff --git a/test/edge_test/SNCLFactory_test.py b/test/edge_test/SNCLFactory_test.py index 44f2d0de0..0920c804c 100644 --- a/test/edge_test/SNCLFactory_test.py +++ b/test/edge_test/SNCLFactory_test.py @@ -1,70 +1,41 @@ -from geomagio.edge import SNCL, SNCLFactory - - -def test_get_sncl(): - assert ( - SNCLFactory(data_format="miniseed").get_sncl( - station="BOU", - data_type="variation", - element="UFU", - interval="minute", - ) - == SNCL(station="BOU", network="NT", channel="UFU", location="R0") - ) - assert ( - SNCLFactory(data_format="legacy").get_sncl( - station="BOU", - data_type="variation", - element="MVH", - interval="minute", - ) - == SNCL(station="BOU", network="NT", channel="MVH", location="R0") - ) +from geomagio.edge import SNCL, SNCLFactory, LegacySNCL def test_get_channel(): - # test miniseed format + """edge_test.SNCLFactory_test.test_get_channel()""" factory = SNCLFactory(data_format="miniseed") - assert factory.get_channel(element="D", interval="minute") == "UFD" + assert factory.get_channel(element="U_Volt", interval="tenhertz") == "BEU" + assert factory.get_channel(element="U_Bin", interval="tenhertz") == "BYU" + assert factory.get_channel(element="D", interval="second") == "LFD" assert factory.get_channel(element="F", interval="minute") == "UFF" - assert factory.get_channel(element="H", interval="minute") == "UFH" - assert factory.get_channel(element="Dst4", interval="minute") == "UX4" + assert factory.get_channel(element="H", interval="hour") == "RFH" + assert factory.get_channel(element="Dst4", interval="day") == "PX4" assert factory.get_channel(element="Dst3", interval="minute") == "UX3" assert factory.get_channel(element="E-E", interval="minute") == "UQE" assert factory.get_channel(element="E-N", interval="minute") == "UQN" - assert factory.get_channel(element="SQ", interval="minute") == "USQ" - assert factory.get_channel(element="SV", interval="minute") == "USV" assert factory.get_channel(element="UK1", interval="minute") == "UK1" - assert factory.get_channel(element="UK2", interval="minute") == "UK2" - assert factory.get_channel(element="UK3", interval="minute") == "UK3" - assert factory.get_channel(element="UK4", interval="minute") == "UK4" - assert factory.get_channel(element="DIST", interval="minute") == "UDT" - assert factory.get_channel(element="DST", interval="minute") == "UGD" assert factory.get_channel(element="U_Dist", interval="minute") == "UFU" + assert factory.get_channel(element="U_SQ", interval="minute") == "UFU" + assert factory.get_channel(element="U_SV", interval="minute") == "UFU" assert factory.get_channel(element="UK1.R0", interval="minute") == "UK1" # test legacy format factory = SNCLFactory(data_format="legacy") - assert factory.get_channel(element="D", interval="minute") == "MVD" + assert factory.get_channel(element="D", interval="second") == "SVD" assert factory.get_channel(element="F", interval="minute") == "MSF" - assert factory.get_channel(element="H", interval="minute") == "MVH" - assert factory.get_channel(element="Dst4", interval="minute") == "MX4" - assert factory.get_channel(element="Dst3", interval="minute") == "MX3" - assert factory.get_channel(element="E-E", interval="minute") == "MQE" + assert factory.get_channel(element="H", interval="hour") == "HVH" + assert factory.get_channel(element="E-E", interval="day") == "DQE" assert factory.get_channel(element="E-N", interval="minute") == "MQN" assert factory.get_channel(element="SQ", interval="minute") == "MSQ" assert factory.get_channel(element="SV", interval="minute") == "MSV" assert factory.get_channel(element="UK1", interval="minute") == "UK1" - assert factory.get_channel(element="UK2", interval="minute") == "UK2" - assert factory.get_channel(element="UK3", interval="minute") == "UK3" - assert factory.get_channel(element="UK4", interval="minute") == "UK4" assert factory.get_channel(element="DIST", interval="minute") == "MDT" assert factory.get_channel(element="DST", interval="minute") == "MGD" - assert factory.get_channel(element="H_Dist", interval="minute") == "MVH" assert factory.get_channel(element="UK1.R0", interval="minute") == "UK1" def test_get_location(): + """edge_test.SNCLFactory_test.test_get_location()""" factory = SNCLFactory(data_format="miniseed") assert factory.get_location(element="D", data_type="variation") == "R0" assert factory.get_location(element="D", data_type="adjusted") == "A0" @@ -74,3 +45,20 @@ def test_get_location(): assert factory.get_location(element="D_Dist", data_type="variation") == "RD" assert factory.get_location(element="D_SQ", data_type="variation") == "RQ" assert factory.get_location(element="D_SV", data_type="variation") == "RV" + + factory = SNCLFactory(data_format="legacy") + assert factory.get_location(element="D", data_type="variation") == "R0" + assert factory.get_location(element="D", data_type="adjusted") == "A0" + assert factory.get_location(element="D", data_type="quasi-definitive") == "Q0" + assert factory.get_location(element="D", data_type="definitive") == "D0" + assert factory.get_location(element="D_Sat", data_type="variation") == "R1" + + +def test_get_sncl(): + """edge_test.SNCLFactory_test.test_get_sncl()""" + assert SNCLFactory(data_format="miniseed").get_sncl( + station="BOU", network="NT", channel="UFU", location="R0" + ) == SNCL(station="BOU", network="NT", channel="UFU", location="R0") + assert SNCLFactory(data_format="legacy").get_sncl( + station="BOU", network="NT", channel="MVH", location="R0" + ) == LegacySNCL(station="BOU", network="NT", channel="MVH", location="R0") diff --git a/test/edge_test/SNCL_test.py b/test/edge_test/SNCL_test.py index 7f59107d9..b2ca4a1be 100644 --- a/test/edge_test/SNCL_test.py +++ b/test/edge_test/SNCL_test.py @@ -2,6 +2,7 @@ from geomagio.edge import SNCL def test_data_type(): + """edge_test.SNCL_test.test_data_type()""" assert SNCL(station="BOU", channel="LFU", location="R0").data_type == "variation" assert SNCL(station="BOU", channel="LFU", location="A0").data_type == "adjusted" assert ( @@ -11,88 +12,8 @@ def test_data_type(): assert SNCL(station="BOU", channel="LFU", location="D0").data_type == "definitive" -def test_interval(): - # miniseed format - assert ( - SNCL( - station="BOU", - channel="BEU", - location="R0", - ).interval - == "tenhertz" - ) - assert ( - SNCL( - station="BOU", - channel="LEU", - location="R0", - ).interval - == "second" - ) - assert ( - SNCL( - station="BOU", - channel="UEU", - location="R0", - ).interval - == "minute" - ) - assert ( - SNCL( - station="BOU", - channel="REU", - location="R0", - ).interval - == "hour" - ) - assert ( - SNCL( - station="BOU", - channel="PEU", - location="R0", - ).interval - == "day" - ) - # legacy format - assert ( - SNCL( - station="BOU", - channel="SVH", - location="R0", - data_format="legacy", - ).interval - == "second" - ) - assert ( - SNCL( - station="BOU", - channel="MVH", - location="R0", - data_format="legacy", - ).interval - == "minute" - ) - assert ( - SNCL( - station="BOU", - channel="HVH", - location="R0", - data_format="legacy", - ).interval - == "hour" - ) - assert ( - SNCL( - station="BOU", - channel="DVH", - location="R0", - data_format="legacy", - ).interval - == "day" - ) - - def test_element(): + """edge_test.SNCL_test.test_element()""" assert ( SNCL( station="BOU", @@ -182,147 +103,64 @@ def test_element(): == "U_Sat" ) + +def test_get_sncl(): + """edge_test.SNCL_test.test_get_sncl()""" + assert SNCL().get_sncl( + station="BOU", data_type="variation", interval="second", element="U" + ) == SNCL(station="BOU", network="NT", channel="LFU", location="R0") + + +def test_interval(): + """edge_test.SNCL_test.test_interval()""" assert ( SNCL( station="BOU", - channel="MVD", - location="R0", - data_format="legacy", - ).element - == "D" - ) - assert ( - SNCL( - station="BOU", - channel="MVU", - location="R0", - data_format="legacy", - ).element - == "U" - ) - assert ( - SNCL( - station="BOU", - channel="MSF", - location="R0", - data_format="legacy", - ).element - == "F" - ) - assert ( - SNCL( - station="BOU", - channel="MVH", - location="R0", - data_format="legacy", - ).element - == "H" - ) - assert ( - SNCL( - station="BOU", - channel="MX4", - location="R0", - data_format="legacy", - ).element - == "Dst4" - ) - assert ( - SNCL( - station="BOU", - channel="MX3", + channel="BEU", location="R0", - data_format="legacy", - ).element - == "Dst3" + ).interval + == "tenhertz" ) assert ( SNCL( station="BOU", - channel="MQE", + channel="LEU", location="R0", - data_format="legacy", - ).element - == "E-E" + ).interval + == "second" ) assert ( SNCL( station="BOU", - channel="MQN", + channel="UEU", location="R0", - data_format="legacy", - ).element - == "E-N" + ).interval + == "minute" ) assert ( SNCL( station="BOU", - channel="MEH", + channel="REU", location="R0", - data_format="legacy", - ).element - == "H_Volt" + ).interval + == "hour" ) assert ( SNCL( station="BOU", - channel="MYH", + channel="PEU", location="R0", - data_format="legacy", - ).element - == "H_Bin" - ) - assert ( - SNCL( - station="BOU", - channel="MVH", - location="R1", - data_format="legacy", - ).element - == "H_Sat" - ) - assert ( - SNCL( - station="BOU", - channel="MVH", - location="RD", - data_format="legacy", - ).element - == "H_Dist" - ) - assert ( - SNCL( - station="BOU", - channel="MVH", - location="RQ", - data_format="legacy", - ).element - == "H_SQ" - ) - assert ( - SNCL( - station="BOU", - channel="MVH", - location="RV", - data_format="legacy", - ).element - == "H_SV" - ) - assert ( - SNCL( - station="BOU", - channel="MDT", - location="RV", - data_format="legacy", - ).element - == "DIST" - ) - assert ( - SNCL( - station="BOU", - channel="MGD", - location="RV", - data_format="legacy", - ).element - == "DST" + ).interval + == "day" ) + + +def test_parse_sncl(): + """edge_test.SNCL_test.test_parse_sncl()""" + assert SNCL(station="BOU", channel="UFU", location="R0").parse_sncl() == { + "station": "BOU", + "network": "NT", + "data_type": "variation", + "element": "U", + "interval": "minute", + } -- GitLab From 486864887e569bd95e0d3d23b0852512f057966d Mon Sep 17 00:00:00 2001 From: pcain-usgs <pcain@usgs.gov> Date: Tue, 18 May 2021 12:00:06 -0600 Subject: [PATCH 6/7] remove SNCLFactory, get channel/location from models --- geomagio/edge/EdgeFactory.py | 9 ++- geomagio/edge/LegacySNCL.py | 81 ++++++++++++++++--- geomagio/edge/MiniSeedFactory.py | 4 +- geomagio/edge/SNCL.py | 104 ++++++++++++++++++++---- geomagio/edge/SNCLFactory.py | 123 ----------------------------- geomagio/edge/__init__.py | 4 - test/edge_test/LegacySNCL_test.py | 28 ++++++- test/edge_test/SNCLFactory_test.py | 64 --------------- test/edge_test/SNCL_test.py | 34 +++++++- 9 files changed, 225 insertions(+), 226 deletions(-) delete mode 100644 geomagio/edge/SNCLFactory.py delete mode 100644 test/edge_test/SNCLFactory_test.py diff --git a/geomagio/edge/EdgeFactory.py b/geomagio/edge/EdgeFactory.py index af226a63a..1190dbb16 100644 --- a/geomagio/edge/EdgeFactory.py +++ b/geomagio/edge/EdgeFactory.py @@ -301,7 +301,7 @@ class EdgeFactory(TimeseriesFactory): obspy.core.trace timeseries trace of the requested channel data """ - sncl = LegacySNCL().get_sncl( + sncl = LegacySNCL.get_sncl( station=observatory, data_type=type, interval=interval, @@ -402,8 +402,11 @@ class EdgeFactory(TimeseriesFactory): ----- RawInputClient seems to only work when sockets are """ - sncl = LegacySNCL().get_sncl( - station=observatory, data_type=type, interval=interval, element=channel + sncl = LegacySNCL.get_sncl( + station=observatory, + data_type=type, + interval=interval, + element=channel, ) now = obspy.core.UTCDateTime(datetime.utcnow()) diff --git a/geomagio/edge/LegacySNCL.py b/geomagio/edge/LegacySNCL.py index be1c3300d..4c747df3a 100644 --- a/geomagio/edge/LegacySNCL.py +++ b/geomagio/edge/LegacySNCL.py @@ -1,7 +1,6 @@ -from __future__ import annotations from typing import Optional -from .SNCL import SNCL +from .SNCL import SNCL, __get_location_start ELEMENT_CONVERSIONS = { # e-field @@ -19,21 +18,20 @@ CHANNEL_CONVERSIONS = { class LegacySNCL(SNCL): + @classmethod def get_sncl( - self, - station: str, + cls, data_type: str, - interval: str, element: str, - ) -> LegacySNCL: - from .SNCLFactory import SNCLFactory - - factory = SNCLFactory(data_format="legacy") + interval: str, + station: str, + network: str = "NT", + ) -> "LegacySNCL": return LegacySNCL( station=station, - network=self.network, - channel=factory.get_channel(element=element, interval=interval), - location=factory.get_location(element=element, data_type=data_type), + network=network, + channel=get_channel(element=element, interval=interval), + location=get_location(element=element, data_type=data_type), ) @property @@ -79,3 +77,62 @@ class LegacySNCL(SNCL): if channel_end in CHANNEL_CONVERSIONS: return CHANNEL_CONVERSIONS[channel_end] return None + + +def get_channel(element: str, interval: str) -> str: + predefined_channel = __check_predefined_channel(element=element, interval=interval) + channel_start = __get_channel_start(interval=interval) + channel_end = __get_channel_end(element=element) + return predefined_channel or (channel_start + channel_end) + + +def get_location(element: str, data_type: str) -> str: + location_start = __get_location_start(data_type=data_type) + location_end = __get_location_end(element=element) + return location_start + location_end + + +def __get_channel_start(interval: str) -> str: + if interval == "second": + return "S" + elif interval == "minute": + return "M" + elif interval == "hour": + return "H" + elif interval == "day": + return "D" + raise ValueError(f" Unexcepted interval: {interval}") + + +def __check_predefined_channel(element: str, interval: str) -> Optional[str]: + if element in ELEMENT_CONVERSIONS: + return __get_channel_start(interval=interval) + ELEMENT_CONVERSIONS[element] + elif len(element) == 3: + return element + # chan.loc format + elif "." in element: + channel = element.split(".")[0] + return channel.strip() + else: + return None + + +def __get_channel_end(element: str) -> str: + channel_middle = "V" + if "_Volt" in element: + channel_middle = "E" + elif "_Bin" in element: + channel_middle = "Y" + elif "_Temp" in element: + channel_middle = "K" + elif element in ["F", "G"]: + channel_middle = "S" + channel_end = element.split("_")[0] + return channel_middle + channel_end + + +def __get_location_end(element: str) -> str: + """Translates element suffix to end of location code""" + if "_Sat" in element: + return "1" + return "0" diff --git a/geomagio/edge/MiniSeedFactory.py b/geomagio/edge/MiniSeedFactory.py index f3530cdd6..ec8b54692 100644 --- a/geomagio/edge/MiniSeedFactory.py +++ b/geomagio/edge/MiniSeedFactory.py @@ -319,7 +319,7 @@ class MiniSeedFactory(TimeseriesFactory): obspy.core.trace timeseries trace of the requested channel data """ - sncl = SNCL().get_sncl( + sncl = SNCL.get_sncl( station=observatory, data_type=type, interval=interval, element=channel ) data = self.client.get_waveforms( @@ -460,7 +460,7 @@ class MiniSeedFactory(TimeseriesFactory): to_write = to_write.split() to_write = TimeseriesUtility.unmask_stream(to_write) # relabel channels from internal to edge conventions - sncl = SNCL().get_sncl( + sncl = SNCL.get_sncl( station=observatory, data_type=type, interval=interval, diff --git a/geomagio/edge/SNCL.py b/geomagio/edge/SNCL.py index 395bfefe5..3dc4b9413 100644 --- a/geomagio/edge/SNCL.py +++ b/geomagio/edge/SNCL.py @@ -1,4 +1,3 @@ -from __future__ import annotations from typing import Dict, Optional from pydantic import BaseModel @@ -18,26 +17,25 @@ CHANNEL_CONVERSIONS = { class SNCL(BaseModel): - station: str = None + station: str network: str = "NT" - channel: str = None - location: str = None + channel: str + location: str + @classmethod def get_sncl( - self, - station: str, + cls, data_type: str, - interval: str, element: str, - ) -> SNCL: - from .SNCLFactory import SNCLFactory - - factory = SNCLFactory(data_format="miniseed") + interval: str, + station: str, + network: str = "NT", + ) -> "SNCL": return SNCL( station=station, - network=self.network, - channel=factory.get_channel(element=element, interval=interval), - location=factory.get_location(element=element, data_type=data_type), + network=network, + channel=get_channel(element=element, interval=interval), + location=get_location(element=element, data_type=data_type), ) def parse_sncl(self) -> Dict: @@ -115,3 +113,81 @@ class SNCL(BaseModel): if channel_end in CHANNEL_CONVERSIONS: return CHANNEL_CONVERSIONS[channel_end] return None + + +def get_channel(element: str, interval: str) -> str: + predefined_channel = __check_predefined_channel(element=element, interval=interval) + channel_start = __get_channel_start(interval=interval) + channel_end = __get_channel_end(element=element) + return predefined_channel or (channel_start + channel_end) + + +def get_location(element: str, data_type: str) -> str: + location_start = __get_location_start(data_type=data_type) + location_end = __get_location_end(element=element) + return location_start + location_end + + +def __get_channel_start(interval: str) -> str: + if interval == "tenhertz": + return "B" + if interval == "second": + return "L" + elif interval == "minute": + return "U" + elif interval == "hour": + return "R" + elif interval == "day": + return "P" + raise ValueError(f" Unexcepted interval: {interval}") + + +def __check_predefined_channel(element: str, interval: str) -> Optional[str]: + if element in ELEMENT_CONVERSIONS: + return __get_channel_start(interval=interval) + ELEMENT_CONVERSIONS[element] + elif len(element) == 3: + return element + # chan.loc format + elif "." in element: + channel = element.split(".")[0] + return channel.strip() + else: + return None + + +def __get_channel_end(element: str) -> str: + channel_middle = "F" + if "_Volt" in element: + channel_middle = "E" + elif "_Bin" in element: + channel_middle = "Y" + elif "_Temp" in element: + channel_middle = "K" + channel_end = element.split("_")[0] + return channel_middle + channel_end + + +def __get_location_start(data_type: str) -> str: + """Translates data type to beginning of location code""" + if data_type == "variation": + return "R" + elif data_type == "adjusted": + return "A" + elif data_type == "quasi-definitive": + return "Q" + elif data_type == "definitive": + return "D" + raise ValueError(f"Unexpected data type: {data_type}") + + +def __get_location_end(element: str) -> str: + """Translates element suffix to end of location code""" + if "_Sat" in element: + return "1" + if "_Dist" in element: + return "D" + if "_SQ" in element: + return "Q" + if "_SV" in element: + return "V" + return "0" diff --git a/geomagio/edge/SNCLFactory.py b/geomagio/edge/SNCLFactory.py deleted file mode 100644 index c4be5e899..000000000 --- a/geomagio/edge/SNCLFactory.py +++ /dev/null @@ -1,123 +0,0 @@ -from typing import Literal, Optional, Union - -from .SNCL import SNCL, ELEMENT_CONVERSIONS as MINISEED_CONVERSIONS -from .LegacySNCL import LegacySNCL, ELEMENT_CONVERSIONS as LEGACY_CONVERSIONS - -INTERVAL_CONVERSIONS = { - "miniseed": { - "tenhertz": "B", - "second": "L", - "minute": "U", - "hour": "R", - "day": "P", - }, - "legacy": { - "second": "S", - "minute": "M", - "hour": "H", - "day": "D", - }, -} - - -class SNCLFactory(object): - def __init__(self, data_format: Literal["miniseed", "legacy"] = "miniseed"): - self.data_format = data_format - - def get_sncl( - self, - station: str, - network: str, - channel: str, - location: str, - ) -> Union[SNCL, LegacySNCL]: - sncl_params = { - "station": station, - "network": network, - "channel": channel, - "location": location, - } - return ( - SNCL(**sncl_params) - if self.data_format == "miniseed" - else LegacySNCL(**sncl_params) - ) - - def get_channel(self, element: str, interval: str) -> str: - predefined_channel = self.__check_predefined_channel( - element=element, interval=interval - ) - channel_start = self.__get_channel_start(interval=interval) - channel_end = self.__get_channel_end(element=element) - return predefined_channel or (channel_start + channel_end) - - def get_location(self, element: str, data_type: str) -> str: - location_start = self.__get_location_start(data_type=data_type) - location_end = self.__get_location_end(element=element) - return location_start + location_end - - def __get_channel_start(self, interval: str) -> str: - interval_conversions = INTERVAL_CONVERSIONS[self.data_format] - try: - return interval_conversions[interval] - except: - raise ValueError(f"Unexpected interval: {interval}") - - def __check_predefined_channel(self, element: str, interval: str) -> Optional[str]: - channel_conversions = ( - MINISEED_CONVERSIONS - if self.data_format == "miniseed" - else LEGACY_CONVERSIONS - ) - - if element in channel_conversions: - return ( - self.__get_channel_start(interval=interval) - + channel_conversions[element] - ) - elif len(element) == 3: - return element - # chan.loc format - elif "." in element: - channel = element.split(".")[0] - return channel.strip() - else: - return None - - def __get_channel_end(self, element: str) -> str: - channel_middle = "F" if self.data_format == "miniseed" else "V" - if "_Volt" in element: - channel_middle = "E" - elif "_Bin" in element: - channel_middle = "Y" - elif "_Temp" in element: - channel_middle = "K" - elif element in ["F", "G"] and self.data_format == "legacy": - channel_middle = "S" - channel_end = element.split("_")[0] - return channel_middle + channel_end - - def __get_location_start(self, data_type: str) -> str: - """Translates data type to beginning of location code""" - if data_type == "variation": - return "R" - elif data_type == "adjusted": - return "A" - elif data_type == "quasi-definitive": - return "Q" - elif data_type == "definitive": - return "D" - raise ValueError(f"Unexpected data type: {data_type}") - - def __get_location_end(self, element: str) -> str: - """Translates element suffix to end of location code""" - if "_Sat" in element: - return "1" - if self.data_format == "miniseed": - if "_Dist" in element: - return "D" - if "_SQ" in element: - return "Q" - if "_SV" in element: - return "V" - return "0" diff --git a/geomagio/edge/__init__.py b/geomagio/edge/__init__.py index 77d5fee30..45b3d49c3 100644 --- a/geomagio/edge/__init__.py +++ b/geomagio/edge/__init__.py @@ -8,7 +8,6 @@ from .MiniSeedFactory import MiniSeedFactory from .MiniSeedInputClient import MiniSeedInputClient from .RawInputClient import RawInputClient from .SNCL import SNCL -from .SNCLFactory import SNCLFactory from .LegacySNCL import LegacySNCL __all__ = [ @@ -18,8 +17,5 @@ __all__ = [ "MiniSeedInputClient", "RawInputClient", "LegacySNCL", - "LegacySNIDE", "SNCL", - "SNCLFactory", - "LegacySNCL", ] diff --git a/test/edge_test/LegacySNCL_test.py b/test/edge_test/LegacySNCL_test.py index 8d7233ffc..adbcc8a83 100644 --- a/test/edge_test/LegacySNCL_test.py +++ b/test/edge_test/LegacySNCL_test.py @@ -1,4 +1,4 @@ -from geomagio.edge import LegacySNCL +from geomagio.edge.LegacySNCL import LegacySNCL, get_channel, get_location def test_data_type(): @@ -111,9 +111,33 @@ def test_element(): ) +def test_get_channel(): + """edge_test.LegacySNCL_test.test_get_channel()""" + assert get_channel(element="D", interval="second") == "SVD" + assert get_channel(element="F", interval="minute") == "MSF" + assert get_channel(element="H", interval="hour") == "HVH" + assert get_channel(element="E-E", interval="day") == "DQE" + assert get_channel(element="E-N", interval="minute") == "MQN" + assert get_channel(element="SQ", interval="minute") == "MSQ" + assert get_channel(element="SV", interval="minute") == "MSV" + assert get_channel(element="UK1", interval="minute") == "UK1" + assert get_channel(element="DIST", interval="minute") == "MDT" + assert get_channel(element="DST", interval="minute") == "MGD" + assert get_channel(element="UK1.R0", interval="minute") == "UK1" + + +def test_get_location(): + """edge_test.LegacySNCL_test.test_get_location()""" + assert get_location(element="D", data_type="variation") == "R0" + assert get_location(element="D", data_type="adjusted") == "A0" + assert get_location(element="D", data_type="quasi-definitive") == "Q0" + assert get_location(element="D", data_type="definitive") == "D0" + assert get_location(element="D_Sat", data_type="variation") == "R1" + + def test_get_sncl(): """edge_test.LegacySNCL_test.test_get_sncl()""" - assert LegacySNCL().get_sncl( + assert LegacySNCL.get_sncl( station="BOU", data_type="variation", interval="second", element="H" ) == LegacySNCL(station="BOU", network="NT", channel="SVH", location="R0") diff --git a/test/edge_test/SNCLFactory_test.py b/test/edge_test/SNCLFactory_test.py deleted file mode 100644 index 0920c804c..000000000 --- a/test/edge_test/SNCLFactory_test.py +++ /dev/null @@ -1,64 +0,0 @@ -from geomagio.edge import SNCL, SNCLFactory, LegacySNCL - - -def test_get_channel(): - """edge_test.SNCLFactory_test.test_get_channel()""" - factory = SNCLFactory(data_format="miniseed") - assert factory.get_channel(element="U_Volt", interval="tenhertz") == "BEU" - assert factory.get_channel(element="U_Bin", interval="tenhertz") == "BYU" - assert factory.get_channel(element="D", interval="second") == "LFD" - assert factory.get_channel(element="F", interval="minute") == "UFF" - assert factory.get_channel(element="H", interval="hour") == "RFH" - assert factory.get_channel(element="Dst4", interval="day") == "PX4" - assert factory.get_channel(element="Dst3", interval="minute") == "UX3" - assert factory.get_channel(element="E-E", interval="minute") == "UQE" - assert factory.get_channel(element="E-N", interval="minute") == "UQN" - assert factory.get_channel(element="UK1", interval="minute") == "UK1" - assert factory.get_channel(element="U_Dist", interval="minute") == "UFU" - assert factory.get_channel(element="U_SQ", interval="minute") == "UFU" - assert factory.get_channel(element="U_SV", interval="minute") == "UFU" - assert factory.get_channel(element="UK1.R0", interval="minute") == "UK1" - - # test legacy format - factory = SNCLFactory(data_format="legacy") - assert factory.get_channel(element="D", interval="second") == "SVD" - assert factory.get_channel(element="F", interval="minute") == "MSF" - assert factory.get_channel(element="H", interval="hour") == "HVH" - assert factory.get_channel(element="E-E", interval="day") == "DQE" - assert factory.get_channel(element="E-N", interval="minute") == "MQN" - assert factory.get_channel(element="SQ", interval="minute") == "MSQ" - assert factory.get_channel(element="SV", interval="minute") == "MSV" - assert factory.get_channel(element="UK1", interval="minute") == "UK1" - assert factory.get_channel(element="DIST", interval="minute") == "MDT" - assert factory.get_channel(element="DST", interval="minute") == "MGD" - assert factory.get_channel(element="UK1.R0", interval="minute") == "UK1" - - -def test_get_location(): - """edge_test.SNCLFactory_test.test_get_location()""" - factory = SNCLFactory(data_format="miniseed") - assert factory.get_location(element="D", data_type="variation") == "R0" - assert factory.get_location(element="D", data_type="adjusted") == "A0" - assert factory.get_location(element="D", data_type="quasi-definitive") == "Q0" - assert factory.get_location(element="D", data_type="definitive") == "D0" - assert factory.get_location(element="D_Sat", data_type="variation") == "R1" - assert factory.get_location(element="D_Dist", data_type="variation") == "RD" - assert factory.get_location(element="D_SQ", data_type="variation") == "RQ" - assert factory.get_location(element="D_SV", data_type="variation") == "RV" - - factory = SNCLFactory(data_format="legacy") - assert factory.get_location(element="D", data_type="variation") == "R0" - assert factory.get_location(element="D", data_type="adjusted") == "A0" - assert factory.get_location(element="D", data_type="quasi-definitive") == "Q0" - assert factory.get_location(element="D", data_type="definitive") == "D0" - assert factory.get_location(element="D_Sat", data_type="variation") == "R1" - - -def test_get_sncl(): - """edge_test.SNCLFactory_test.test_get_sncl()""" - assert SNCLFactory(data_format="miniseed").get_sncl( - station="BOU", network="NT", channel="UFU", location="R0" - ) == SNCL(station="BOU", network="NT", channel="UFU", location="R0") - assert SNCLFactory(data_format="legacy").get_sncl( - station="BOU", network="NT", channel="MVH", location="R0" - ) == LegacySNCL(station="BOU", network="NT", channel="MVH", location="R0") diff --git a/test/edge_test/SNCL_test.py b/test/edge_test/SNCL_test.py index b2ca4a1be..ea92aa524 100644 --- a/test/edge_test/SNCL_test.py +++ b/test/edge_test/SNCL_test.py @@ -1,4 +1,4 @@ -from geomagio.edge import SNCL +from geomagio.edge.SNCL import SNCL, get_channel, get_location def test_data_type(): @@ -104,9 +104,39 @@ def test_element(): ) +def test_get_channel(): + """edge_test.SNCL_test.test_get_channel()""" + assert get_channel(element="U_Volt", interval="tenhertz") == "BEU" + assert get_channel(element="U_Bin", interval="tenhertz") == "BYU" + assert get_channel(element="D", interval="second") == "LFD" + assert get_channel(element="F", interval="minute") == "UFF" + assert get_channel(element="H", interval="hour") == "RFH" + assert get_channel(element="Dst4", interval="day") == "PX4" + assert get_channel(element="Dst3", interval="minute") == "UX3" + assert get_channel(element="E-E", interval="minute") == "UQE" + assert get_channel(element="E-N", interval="minute") == "UQN" + assert get_channel(element="UK1", interval="minute") == "UK1" + assert get_channel(element="U_Dist", interval="minute") == "UFU" + assert get_channel(element="U_SQ", interval="minute") == "UFU" + assert get_channel(element="U_SV", interval="minute") == "UFU" + assert get_channel(element="UK1.R0", interval="minute") == "UK1" + + +def test_get_location(): + """edge_test.SNCL_test.test_get_location()""" + assert get_location(element="D", data_type="variation") == "R0" + assert get_location(element="D", data_type="adjusted") == "A0" + assert get_location(element="D", data_type="quasi-definitive") == "Q0" + assert get_location(element="D", data_type="definitive") == "D0" + assert get_location(element="D_Sat", data_type="variation") == "R1" + assert get_location(element="D_Dist", data_type="variation") == "RD" + assert get_location(element="D_SQ", data_type="variation") == "RQ" + assert get_location(element="D_SV", data_type="variation") == "RV" + + def test_get_sncl(): """edge_test.SNCL_test.test_get_sncl()""" - assert SNCL().get_sncl( + assert SNCL.get_sncl( station="BOU", data_type="variation", interval="second", element="U" ) == SNCL(station="BOU", network="NT", channel="LFU", location="R0") -- GitLab From 712f5c99e79ba6abad39143c5b31808e39377aef Mon Sep 17 00:00:00 2001 From: pcain-usgs <pcain@usgs.gov> Date: Wed, 16 Jun 2021 15:59:58 -0600 Subject: [PATCH 7/7] move _get_element outside of classes, chain commands --- geomagio/edge/LegacySNCL.py | 80 ++++++++++++++++---------------- geomagio/edge/SNCL.py | 92 ++++++++++++++++++------------------- 2 files changed, 84 insertions(+), 88 deletions(-) diff --git a/geomagio/edge/LegacySNCL.py b/geomagio/edge/LegacySNCL.py index 4c747df3a..a2478b599 100644 --- a/geomagio/edge/LegacySNCL.py +++ b/geomagio/edge/LegacySNCL.py @@ -1,6 +1,6 @@ from typing import Optional -from .SNCL import SNCL, __get_location_start +from .SNCL import SNCL, _get_location_start ELEMENT_CONVERSIONS = { # e-field @@ -36,9 +36,9 @@ class LegacySNCL(SNCL): @property def element(self) -> str: - predefined_element = self.__check_predefined_element() - element = self.__get_element() - return predefined_element or element + return _check_predefined_element(channel=self.channel) or _get_element( + channel=self.channel, location=self.location + ) @property def interval(self) -> str: @@ -53,46 +53,25 @@ class LegacySNCL(SNCL): return "day" raise ValueError(f"Unexcepted interval code: {channel_start}") - def __get_element(self): - """Translates channel/location to element""" - element_start = self.channel[2] - channel = self.channel - channel_middle = channel[1] - location_end = self.location[1] - if channel_middle in ["Q", "E"]: - element_end = "_Volt" - elif channel_middle == "Y": - element_end = "_Bin" - elif channel_middle == "K": - element_end = "_Temp" - elif location_end == "1": - element_end = "_Sat" - else: - element_end = "" - return element_start + element_end - - def __check_predefined_element(self) -> Optional[str]: - channel = self.channel - channel_end = channel[1:] - if channel_end in CHANNEL_CONVERSIONS: - return CHANNEL_CONVERSIONS[channel_end] - return None - def get_channel(element: str, interval: str) -> str: - predefined_channel = __check_predefined_channel(element=element, interval=interval) - channel_start = __get_channel_start(interval=interval) - channel_end = __get_channel_end(element=element) - return predefined_channel or (channel_start + channel_end) + return _check_predefined_channel(element=element, interval=interval) or ( + _get_channel_start(interval=interval) + _get_channel_end(element=element) + ) def get_location(element: str, data_type: str) -> str: - location_start = __get_location_start(data_type=data_type) - location_end = __get_location_end(element=element) - return location_start + location_end + return _get_location_start(data_type=data_type) + _get_location_end(element=element) + +def _check_predefined_element(channel: str) -> Optional[str]: + channel_end = channel[1:] + if channel_end in CHANNEL_CONVERSIONS: + return CHANNEL_CONVERSIONS[channel_end] + return None -def __get_channel_start(interval: str) -> str: + +def _get_channel_start(interval: str) -> str: if interval == "second": return "S" elif interval == "minute": @@ -104,9 +83,28 @@ def __get_channel_start(interval: str) -> str: raise ValueError(f" Unexcepted interval: {interval}") -def __check_predefined_channel(element: str, interval: str) -> Optional[str]: +def _get_element(channel: str, location: str) -> str: + """Translates channel/location to element""" + element_start = channel[2] + channel = channel + channel_middle = channel[1] + location_end = location[1] + if channel_middle in ["Q", "E"]: + element_end = "_Volt" + elif channel_middle == "Y": + element_end = "_Bin" + elif channel_middle == "K": + element_end = "_Temp" + elif location_end == "1": + element_end = "_Sat" + else: + element_end = "" + return element_start + element_end + + +def _check_predefined_channel(element: str, interval: str) -> Optional[str]: if element in ELEMENT_CONVERSIONS: - return __get_channel_start(interval=interval) + ELEMENT_CONVERSIONS[element] + return _get_channel_start(interval=interval) + ELEMENT_CONVERSIONS[element] elif len(element) == 3: return element # chan.loc format @@ -117,7 +115,7 @@ def __check_predefined_channel(element: str, interval: str) -> Optional[str]: return None -def __get_channel_end(element: str) -> str: +def _get_channel_end(element: str) -> str: channel_middle = "V" if "_Volt" in element: channel_middle = "E" @@ -131,7 +129,7 @@ def __get_channel_end(element: str) -> str: return channel_middle + channel_end -def __get_location_end(element: str) -> str: +def _get_location_end(element: str) -> str: """Translates element suffix to end of location code""" if "_Sat" in element: return "1" diff --git a/geomagio/edge/SNCL.py b/geomagio/edge/SNCL.py index 3dc4b9413..de292587c 100644 --- a/geomagio/edge/SNCL.py +++ b/geomagio/edge/SNCL.py @@ -63,9 +63,9 @@ class SNCL(BaseModel): @property def element(self) -> str: - predefined_element = self.__check_predefined_element() - element = self.__get_element() - return predefined_element or element + return _check_predefined_element(channel=self.channel) or _get_element( + channel=self.channel, location=self.location + ) @property def interval(self) -> str: @@ -83,52 +83,25 @@ class SNCL(BaseModel): return "day" raise ValueError(f"Unexcepted interval code: {channel_start}") - def __get_element(self): - """Translates channel/location to element""" - element_start = self.channel[2] - channel = self.channel - channel_middle = channel[1] - location_end = self.location[1] - if channel_middle == "E": - element_end = "_Volt" - elif channel_middle == "Y": - element_end = "_Bin" - elif channel_middle == "K": - element_end = "_Temp" - elif location_end == "1": - element_end = "_Sat" - elif location_end == "D": - element_end = "_Dist" - elif location_end == "Q": - element_end = "_SQ" - elif location_end == "V": - element_end = "_SV" - else: - element_end = "" - return element_start + element_end - - def __check_predefined_element(self) -> Optional[str]: - channel = self.channel - channel_end = channel[1:] - if channel_end in CHANNEL_CONVERSIONS: - return CHANNEL_CONVERSIONS[channel_end] - return None - def get_channel(element: str, interval: str) -> str: - predefined_channel = __check_predefined_channel(element=element, interval=interval) - channel_start = __get_channel_start(interval=interval) - channel_end = __get_channel_end(element=element) - return predefined_channel or (channel_start + channel_end) + return _check_predefined_channel(element=element, interval=interval) or ( + _get_channel_start(interval=interval) + _get_channel_end(element=element) + ) def get_location(element: str, data_type: str) -> str: - location_start = __get_location_start(data_type=data_type) - location_end = __get_location_end(element=element) - return location_start + location_end + return _get_location_start(data_type=data_type) + _get_location_end(element=element) + +def _check_predefined_element(channel: str) -> Optional[str]: + channel_end = channel[1:] + if channel_end in CHANNEL_CONVERSIONS: + return CHANNEL_CONVERSIONS[channel_end] + return None -def __get_channel_start(interval: str) -> str: + +def _get_channel_start(interval: str) -> str: if interval == "tenhertz": return "B" if interval == "second": @@ -142,9 +115,34 @@ def __get_channel_start(interval: str) -> str: raise ValueError(f" Unexcepted interval: {interval}") -def __check_predefined_channel(element: str, interval: str) -> Optional[str]: +def _get_element(channel: str, location: str) -> str: + """Translates channel/location to element""" + element_start = channel[2] + channel = channel + channel_middle = channel[1] + location_end = location[1] + if channel_middle == "E": + element_end = "_Volt" + elif channel_middle == "Y": + element_end = "_Bin" + elif channel_middle == "K": + element_end = "_Temp" + elif location_end == "1": + element_end = "_Sat" + elif location_end == "D": + element_end = "_Dist" + elif location_end == "Q": + element_end = "_SQ" + elif location_end == "V": + element_end = "_SV" + else: + element_end = "" + return element_start + element_end + + +def _check_predefined_channel(element: str, interval: str) -> Optional[str]: if element in ELEMENT_CONVERSIONS: - return __get_channel_start(interval=interval) + ELEMENT_CONVERSIONS[element] + return _get_channel_start(interval=interval) + ELEMENT_CONVERSIONS[element] elif len(element) == 3: return element # chan.loc format @@ -155,7 +153,7 @@ def __check_predefined_channel(element: str, interval: str) -> Optional[str]: return None -def __get_channel_end(element: str) -> str: +def _get_channel_end(element: str) -> str: channel_middle = "F" if "_Volt" in element: channel_middle = "E" @@ -167,7 +165,7 @@ def __get_channel_end(element: str) -> str: return channel_middle + channel_end -def __get_location_start(data_type: str) -> str: +def _get_location_start(data_type: str) -> str: """Translates data type to beginning of location code""" if data_type == "variation": return "R" @@ -180,7 +178,7 @@ def __get_location_start(data_type: str) -> str: raise ValueError(f"Unexpected data type: {data_type}") -def __get_location_end(element: str) -> str: +def _get_location_end(element: str) -> str: """Translates element suffix to end of location code""" if "_Sat" in element: return "1" -- GitLab