From d76d628511f19d3f5fb8adbcfd5300350406379e Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Fri, 21 Feb 2025 14:07:23 -0700 Subject: [PATCH 1/2] Added NEIC client parameters to FDSNFactory.py --- geomagio/edge/FDSNFactory.py | 89 ++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/geomagio/edge/FDSNFactory.py b/geomagio/edge/FDSNFactory.py index b72228e8..a15f25af 100644 --- a/geomagio/edge/FDSNFactory.py +++ b/geomagio/edge/FDSNFactory.py @@ -12,6 +12,7 @@ from obspy import Stream, UTCDateTime, Trace, read, read_inventory from obspy.clients.fdsn.header import FDSNNoDataException from obspy.clients.iris import Client from obspy.clients.fdsn import Client as FDSNClient +from obspy.clients import neic from .. import ChannelConverter, TimeseriesUtility from ..geomag_types import DataInterval, DataType @@ -68,13 +69,15 @@ class FDSNFactory(TimeseriesFactory): Notes ----- - This is designed to read from the FDSN Client, but it + This is designed to read from the FDSN Client and EDGE if data is less than 1 day old, but it currently only writes to an edge. """ def __init__( self, base_url: str = "http://service.iris.edu", + host: Optional[str] = None, + port: Optional[int] = None, tag: str = "GeomagAlg", observatory: Optional[str] = None, network: str = "NT", @@ -90,6 +93,8 @@ class FDSNFactory(TimeseriesFactory): ): TimeseriesFactory.__init__(self, observatory, channels, type, interval) self.Client = FDSNClient(base_url) + self.port = port # Need to add this paramter for later logic + self.host = host self.remove_sensitivity = remove_sensitivity self.tag = tag self.interval = interval @@ -182,7 +187,6 @@ class FDSNFactory(TimeseriesFactory): # # restore stdout # sys.stdout = original_stdout self._post_process(timeseries, starttime, endtime, channels) - return timeseries def _get_timeseries( @@ -229,36 +233,69 @@ class FDSNFactory(TimeseriesFactory): network=self.network, location=self.locationCode, ) - # geomag-algorithms *should* treat starttime/endtime as inclusive everywhere; # according to its author, EdgeCWB is inclusive of starttime, but exclusive of # endtime, to satisfy seismic standards/requirements, to precision delta/2; half_delta = TimeseriesUtility.get_delta_from_interval(interval) / 2 - # Rotate the trace into a right handed coordinate frame. - # This will work assuming the metadata is reported correctly. - # Channel that require rotations channel_rotations = ["X", "Y", "Z"] try: - data = self.Client.get_waveforms( + # Create Inventory Object for rotations and attach response + inv = self.Client.get_stations( network=sncl.network, station=sncl.station, - location=sncl.location, - channel=sncl.channel, + location=sncl.location, # Use location if necessary + channel=sncl.channel, # Request *F1, *F2, and *FZ starttime=starttime, - endtime=endtime + half_delta, - attach_response=True, + endtime=endtime, + level="response", ) + + # Determine whether to use FDSN Client or request data from EDGE + if endtime >= (UTCDateTime.now() - 86400): + print("The endtime is less than a day later!", endtime) + + self.host = "137.227.252.145" + self.port = 2061 + # use NEIC Client instead + neic_client = neic.Client(self.host, self.port) + + neic_channel = [ch.strip() for ch in sncl.channel.split(",")] + data = Stream() + + for single_channel in neic_channel: + data += neic_client.get_waveforms( + network=sncl.network, + station=sncl.station, + location=sncl.location, + channel=single_channel, + starttime=starttime, + endtime=endtime + half_delta, + ) + + data.attach_response(inv) + + else: + + data = self.Client.get_waveforms( + network=sncl.network, + station=sncl.station, + location=sncl.location, + channel=sncl.channel, + starttime=starttime, + endtime=endtime + half_delta, + attach_response=True, + ) + # Perfrom calibrations to properly remove response/sensitivity data = self._calibrate_sensitivty_and_response(data) if channel in channel_rotations: data = self._rotate_and_return_requested_channel( - data, sncl, starttime, endtime, channel + data, sncl, inv, starttime, endtime, channel ) - except FDSNNoDataException: data = Stream() print( @@ -368,6 +405,7 @@ class FDSNFactory(TimeseriesFactory): self, data: Stream, sncl, + inv, starttime: UTCDateTime, endtime: UTCDateTime, requested_channel: str, @@ -378,19 +416,22 @@ class FDSNFactory(TimeseriesFactory): """ # Initialize FDSN client and get the necessary data - FDSN = self.Client + # FDSN = self.Client # Determine if the requested channel is X, Y, or - inv = FDSN.get_stations( - network=sncl.network, - station=sncl.station, - location=sncl.location, # Use location if necessary - channel=sncl.channel, # Request *F1, *F2, and *FZ - starttime=starttime, - endtime=endtime, - level="response", + # inv = FDSN.get_stations( + # network=sncl.network, + # station=sncl.station, + # location=sncl.location, # Use location if necessary + # channel=sncl.channel, # Request *F1, *F2, and *FZ + # starttime=starttime, + # endtime=endtime, + # level="response", + # ) + print( + "The SNCL Channel being requested for teh inventory object in rotations: ", + sncl.channel, ) - # Rotate the stream to ZNE data.rotate(method="->ZNE", inventory=inv) @@ -445,4 +486,6 @@ class FDSNFactory(TimeseriesFactory): # Geomag Program observatories use 2nd order instrument_polynomial # to capture both offset and scale, but no frequency response data.remove_response() + else: + print("NO RESPONSE ATTIBUTE WAS DEALT WITH") return data -- GitLab From 3795a9bbd24313c7ec502ce1fb9c01a2e407e700 Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Mon, 3 Mar 2025 15:35:03 -0700 Subject: [PATCH 2/2] Addressed Josh's Comments --- geomagio/edge/FDSNFactory.py | 44 ++++++++++-------------------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/geomagio/edge/FDSNFactory.py b/geomagio/edge/FDSNFactory.py index a15f25af..4445d98c 100644 --- a/geomagio/edge/FDSNFactory.py +++ b/geomagio/edge/FDSNFactory.py @@ -69,15 +69,14 @@ class FDSNFactory(TimeseriesFactory): Notes ----- - This is designed to read from the FDSN Client and EDGE if data is less than 1 day old, but it - currently only writes to an edge. + This is designed to read from the FDSN Client and EDGE if data is less than 1 day old """ def __init__( self, - base_url: str = "http://service.iris.edu", - host: Optional[str] = None, - port: Optional[int] = None, + fdsn_url: str = "http://service.iris.edu", + host: Optional[str] = "edgecwb.usgs.gov", + port: Optional[int] = 2061, tag: str = "GeomagAlg", observatory: Optional[str] = None, network: str = "NT", @@ -92,7 +91,7 @@ class FDSNFactory(TimeseriesFactory): ] = None, # Accepts "remove_sensitivity" or "remove_response" ): TimeseriesFactory.__init__(self, observatory, channels, type, interval) - self.Client = FDSNClient(base_url) + self.Client = FDSNClient(fdsn_url) self.port = port # Need to add this paramter for later logic self.host = host self.remove_sensitivity = remove_sensitivity @@ -254,11 +253,11 @@ class FDSNFactory(TimeseriesFactory): ) # Determine whether to use FDSN Client or request data from EDGE - if endtime >= (UTCDateTime.now() - 86400): - print("The endtime is less than a day later!", endtime) + oldest_neic_utc = UTCDateTime.now() - ( + 86_400 * 60 + ) # `date` ensures a midnight boundary + if starttime >= oldest_neic_utc: - self.host = "137.227.252.145" - self.port = 2061 # use NEIC Client instead neic_client = neic.Client(self.host, self.port) @@ -275,8 +274,6 @@ class FDSNFactory(TimeseriesFactory): endtime=endtime + half_delta, ) - data.attach_response(inv) - else: data = self.Client.get_waveforms( @@ -286,9 +283,11 @@ class FDSNFactory(TimeseriesFactory): channel=sncl.channel, starttime=starttime, endtime=endtime + half_delta, - attach_response=True, ) + # Attach the channel response. This must be done before the _calibarate_sensitivity_and_response function is called + data.attach_response(inv) + # Perfrom calibrations to properly remove response/sensitivity data = self._calibrate_sensitivty_and_response(data) @@ -415,23 +414,6 @@ class FDSNFactory(TimeseriesFactory): Channels are mapped as follows: 'X' -> '*F2', 'Y' -> '*F1', 'Z' -> '*FZ'. """ - # Initialize FDSN client and get the necessary data - # FDSN = self.Client - # Determine if the requested channel is X, Y, or - - # inv = FDSN.get_stations( - # network=sncl.network, - # station=sncl.station, - # location=sncl.location, # Use location if necessary - # channel=sncl.channel, # Request *F1, *F2, and *FZ - # starttime=starttime, - # endtime=endtime, - # level="response", - # ) - print( - "The SNCL Channel being requested for teh inventory object in rotations: ", - sncl.channel, - ) # Rotate the stream to ZNE data.rotate(method="->ZNE", inventory=inv) @@ -486,6 +468,4 @@ class FDSNFactory(TimeseriesFactory): # Geomag Program observatories use 2nd order instrument_polynomial # to capture both offset and scale, but no frequency response data.remove_response() - else: - print("NO RESPONSE ATTIBUTE WAS DEALT WITH") return data -- GitLab