diff --git a/geomagio/edge/FDSNFactory.py b/geomagio/edge/FDSNFactory.py index b72228e87d7201bd645cf1fc2df6c6a7e9123ae9..4445d98c087d646c4313227b0715699a36112b27 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,14 @@ class FDSNFactory(TimeseriesFactory): Notes ----- - This is designed to read from the FDSN Client, 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", + 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", @@ -89,7 +91,9 @@ 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 self.tag = tag self.interval = interval @@ -182,7 +186,6 @@ class FDSNFactory(TimeseriesFactory): # # restore stdout # sys.stdout = original_stdout self._post_process(timeseries, starttime, endtime, channels) - return timeseries def _get_timeseries( @@ -229,36 +232,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 + oldest_neic_utc = UTCDateTime.now() - ( + 86_400 * 60 + ) # `date` ensures a midnight boundary + if starttime >= oldest_neic_utc: + + # 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, + ) + + 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 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) 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 +404,7 @@ class FDSNFactory(TimeseriesFactory): self, data: Stream, sncl, + inv, starttime: UTCDateTime, endtime: UTCDateTime, requested_channel: str, @@ -377,20 +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", - ) - # Rotate the stream to ZNE data.rotate(method="->ZNE", inventory=inv)