diff --git a/etc/adjusted/BOU201601vmin.min b/etc/adjusted/BOU201601vmin.min index 57c20c44233ae76dfd9dae307ce91c14086b4651..83ef32f4830f78ffc089e167dc6230832db4e2ee 100644 --- a/etc/adjusted/BOU201601vmin.min +++ b/etc/adjusted/BOU201601vmin.min @@ -5,7 +5,7 @@ Geodetic Latitude 40.137 | Geodetic Longitude 254.764 | Elevation 1682 | - Reported HEZF | + Reported UVWF | Sensor Orientation HDZF | Digital Sampling 100.0 second | Data Interval Type filtered 1-minute (00:15-01:45) | @@ -19,7 +19,7 @@ # CONDITIONS OF USE: The Conditions of Use for data provided | # through INTERMAGNET and acknowledgement templates can be found at | # www.intermagnet.org | -DATE TIME DOY BOUH BOUE BOUZ BOUF | +DATE TIME DOY BOUU BOUV BOUW BOUF | 2016-01-01 00:00:00.000 001 20735.93 -99.77 47370.21 52248.63 2016-01-01 00:01:00.000 001 20735.48 -95.30 47370.53 52248.72 2016-01-01 00:02:00.000 001 20736.30 -91.25 47371.05 52249.49 diff --git a/etc/adjusted/BOU202005adj.min b/etc/adjusted/BOU202005adj.min index 55f8fcc64580668ad815ae8706c1628cbbea0285..551fd3ed7ec4fabb3ecf4b5a360b782ce4f45b3c 100644 --- a/etc/adjusted/BOU202005adj.min +++ b/etc/adjusted/BOU202005adj.min @@ -5,7 +5,7 @@ Geodetic Latitude 40.137 | Geodetic Longitude 254.763 | Elevation 1682 | - Reported HENULNUL | + Reported UVNULNUL | Sensor Orientation HDZF | Digital Sampling 0.01 second | Data Interval Type filtered 1-minute (00:15-01:45) | @@ -17,7 +17,7 @@ # CONDITIONS OF USE: The Conditions of Use for data provided | # through INTERMAGNET and acknowledgement templates can be found at | # www.intermagnet.org | -DATE TIME DOY BOUH BOUE BOUNUL BOUNUL | +DATE TIME DOY BOUU BOUV BOUNUL BOUNUL | 2020-05-20 16:15:00.000 141 -20799.04 80.92 99999.00 99999.00 2020-05-20 16:16:00.000 141 -20798.26 79.97 99999.00 99999.00 2020-05-20 16:17:00.000 141 -20799.43 81.22 99999.00 99999.00 diff --git a/etc/adjusted/BOU202005vmin.min b/etc/adjusted/BOU202005vmin.min index 545671c9b844f2f36fa64467d195b52c2780c762..f3d0f15bc47bdb0d77d374942c155d20e95955ee 100644 --- a/etc/adjusted/BOU202005vmin.min +++ b/etc/adjusted/BOU202005vmin.min @@ -5,7 +5,7 @@ Geodetic Latitude 40.137 | Geodetic Longitude 254.763 | Elevation 1682 | - Reported HENULNUL | + Reported UVNULNUL | Sensor Orientation HDZF | Digital Sampling 0.01 second | Data Interval Type filtered 1-minute (00:15-01:45) | @@ -19,7 +19,7 @@ # CONDITIONS OF USE: The Conditions of Use for data provided | # through INTERMAGNET and acknowledgement templates can be found at | # www.intermagnet.org | -DATE TIME DOY BOUH BOUE BOUNUL BOUNUL | +DATE TIME DOY BOUU BOUV BOUNUL BOUNUL | 2020-05-20 16:15:00.000 141 20799.04 -80.92 99999.00 99999.00 2020-05-20 16:16:00.000 141 20798.26 -79.97 99999.00 99999.00 2020-05-20 16:17:00.000 141 20799.43 -81.22 99999.00 99999.00 diff --git a/geomagio/ChannelConverter.py b/geomagio/ChannelConverter.py index a7c3bfc8b255f77521bce41916ab0b7484a02693..3884af3d286050fba482a6eee352432d87c94c9f 100644 --- a/geomagio/ChannelConverter.py +++ b/geomagio/ChannelConverter.py @@ -5,7 +5,7 @@ the geomagnetic community. We use three coordinate systems. Geo: Based on Geographic North. X, Y, Z X is north, Y is east -Obs: Based on the observatories orientaion. H, E, Z [d] +Obs: Based on the observatories orientaion. U, V, W [d] Mag: Based on Magnetic North. H, D, Z [E] d0: Declination baseline in radians @@ -29,15 +29,15 @@ R2M = 180.0 / numpy.pi * 60 # Radians to Minutes # ### -def get_geo_from_obs(h, e, d0=0): +def get_geo_from_obs(u, v, d0=0): """gets the geographical components given the observatory components. Parameters __________ - h: array_like - the h component from the observatory - e: array_like - the e component from the observatory + u: array_like + the u component from the observatory + v: array_like + the v component from the observatory d0: float the declination baseline angle in radians @@ -47,7 +47,7 @@ def get_geo_from_obs(h, e, d0=0): [0]: x component as a float [1]: y component as a float """ - mag_h, mag_d = get_mag_from_obs(h, e, d0) + mag_h, mag_d = get_mag_from_obs(u, v, d0) return get_geo_from_mag(mag_h, mag_d) @@ -112,15 +112,15 @@ def get_geo_y_from_mag(h, d): # ### # get magnetic north coordinates from.... # ### -def get_mag_from_obs(h, e, d0=0): +def get_mag_from_obs(u, v, d0=0): """gets the magnetic north components given the observatory components. Parameters __________ - h: array_like - the h component from the observatory - e: array_like - the e component from the observatory + u: array_like + the u component from the observatory + v: array_like + the v component from the observatory d0: float the declination baseline angle in radians @@ -130,8 +130,8 @@ def get_mag_from_obs(h, e, d0=0): [0]: total h component as a float [1]: total d declination as a float """ - mag_h = get_mag_h_from_obs(h, e) - mag_d = get_mag_d_from_obs(h, e, d0) + mag_h = get_mag_h_from_obs(u, v) + mag_d = get_mag_d_from_obs(u, v, d0) return (mag_h, mag_d) @@ -156,15 +156,15 @@ def get_mag_from_geo(x, y): return (mag_h, mag_d) -def get_mag_d_from_obs(h, e, d0=0): +def get_mag_d_from_obs(u, v, d0=0): """gets the magnetic d component given the observatory components. Parameters __________ - h: array_like - the h component from the observatory - e: array_like - the e component from the observatory + u: array_like + the u component from the observatory + v: array_like + the v component from the observatory d0: float the declination baseline angle in radians @@ -173,7 +173,7 @@ def get_mag_d_from_obs(h, e, d0=0): array_like the total magnetic declination """ - return numpy.add(d0, get_obs_d_from_obs(h, e)) + return numpy.add(d0, get_obs_d_from_obs(u, v)) def get_mag_d_from_geo(x, y): @@ -194,22 +194,22 @@ def get_mag_d_from_geo(x, y): return numpy.arctan2(y, x) -def get_mag_h_from_obs(h, e): +def get_mag_h_from_obs(u, v): """gets the magnetic h component given the observatory components. Parameters __________ - h: array_like - the h component from the observatory - e: array_like - the e component from the observatory + u: array_like + the u component from the observatory + v: array_like + the v component from the observatory Returns _______ array_like the total magnetic h component """ - return numpy.hypot(h, e) + return numpy.hypot(u, v) def get_mag_h_from_geo(x, y): @@ -271,32 +271,32 @@ def get_obs_from_mag(h, d, d0=0): Returns _______ tuple of array_like - [0]: observatory h component - [1]: observatory e component + [0]: observatory u component + [1]: observatory v component [2]: observatory d declination """ - obs_h = get_obs_h_from_mag(h, d, d0) - obs_e = get_obs_e_from_mag(h, d, d0) - return (obs_h, obs_e) + obs_u = get_obs_u_from_mag(h, d, d0) + obs_v = get_obs_v_from_mag(h, d, d0) + return (obs_u, obs_v) # inividual get obs from calls -def get_obs_d_from_obs(h, e): +def get_obs_d_from_obs(u, v): """gets the observatory d declination given the observatory components. Parameters __________ - h: array_like - the h component from the observatory - e: array_like - the e component from the observatory + u: array_like + the u component from the observatory + v: array_like + the v component from the observatory Returns _______ array_like the observatory d declination """ - return numpy.arctan2(e, h) + return numpy.arctan2(v, u) def get_obs_d_from_mag_d(d, d0=0): @@ -318,8 +318,8 @@ def get_obs_d_from_mag_d(d, d0=0): return numpy.subtract(d, d0) -def get_obs_e_from_mag(h, d, d0=0): - """gets the observatory e component given the magnetic components. +def get_obs_v_from_mag(h, d, d0=0): + """gets the observatory v component given the magnetic components. Parameters __________ @@ -333,32 +333,32 @@ def get_obs_e_from_mag(h, d, d0=0): Returns _______ array_like - the observatory e component + the observatory v component """ obs_d = get_obs_d_from_mag_d(d, d0) return numpy.multiply(h, numpy.sin(obs_d)) -def get_obs_e_from_obs(h, d): - """gets the observatory e component given the observatory components. +def get_obs_v_from_obs(h, d): + """gets the observatory v component given the observatory components. Parameters __________ - h: array_like - the observatory h component. + u: array_like + the observatory u component. d: array_like the observatory d declination. Returns _______ array_like - the observatory e component + the observatory v component """ return numpy.multiply(h, numpy.tan(d)) -def get_obs_h_from_mag(h, d, d0=0): - """gets the observatory h component given the magnetic north components +def get_obs_u_from_mag(h, d, d0=0): + """gets the observatory u component given the magnetic north components Parameters __________ @@ -372,7 +372,7 @@ def get_obs_h_from_mag(h, d, d0=0): Returns _______ array_like - the observatory h component + the observatory u component """ obs_d = get_obs_d_from_mag_d(d, d0) return numpy.multiply(h, numpy.cos(obs_d)) @@ -405,7 +405,7 @@ def get_computed_f_using_squares(x, y, z): Notes ----- This works for geographic coordinates, or observatory coordinates. - ie x, y, z or h, e, z + ie x, y, z or u, v, w We're using variables x,y,z to represent generic cartisian coordinates. """ x2 = numpy.square(x) diff --git a/geomagio/StreamConverter.py b/geomagio/StreamConverter.py index 4ef3232c5db1ef5b0ec7cf4eb62357a9d5550413..4677acee27626dc968216793895ba4102668b302 100644 --- a/geomagio/StreamConverter.py +++ b/geomagio/StreamConverter.py @@ -3,7 +3,7 @@ We use three coordinate systems. Geo: Based on Geographic North. X, Y, Z, F X is north, Y is east, Z is down -Obs: Based on the observatories orientaion. H, E, Z, F, d0 +Obs: Based on the observatories orientaion. U, V, W, F, d0 Mag: Based on Magnetic North. H, D, Z, F """ from __future__ import absolute_import @@ -48,7 +48,7 @@ def get_geo_from_obs(obs): Parameters ---------- stream : obspy.core.Stream - stream containing observatory components H, D or E, Z, and F. + stream containing observatory components U, D or V, W, and F. Returns ------- @@ -86,20 +86,20 @@ def get_deltaf_from_obs(obs): Parameters ---------- obs: obspy.core.Stream - stream containing the observatory components H, D or E, Z, and F. + stream containing the observatory components U, D or V, W, and F. Returns ------- obspy.core.Stream stream object containing delta f values """ - h = obs.select(channel="H")[0] - z = obs.select(channel="Z")[0] + u = obs.select(channel="U")[0] + w = obs.select(channel="W")[0] fs = obs.select(channel="F")[0] - e = __get_obs_e_from_obs(obs) - fv = ChannelConverter.get_computed_f_using_squares(h, e, z) + v = __get_obs_v_from_obs(obs) + fv = ChannelConverter.get_computed_f_using_squares(u, v, w) G = ChannelConverter.get_deltaf(fv, fs) - return obspy.core.Stream((__get_trace("G", h.stats, G),)) + return obspy.core.Stream((__get_trace("G", u.stats, G),)) def get_mag_from_geo(geo): @@ -137,28 +137,28 @@ def get_mag_from_obs(obs): Parameters ---------- obs : obspy.core.Stream - stream containing observatory components H, D or E, Z, and F. + stream containing observatory components U, D or V, W, and F. Returns ------- obspy.core.Stream new stream object containing magnetic components H, D, Z, and F. """ - h = obs.select(channel="H")[0] - e = __get_obs_e_from_obs(obs) - z = obs.select(channel="Z") + u = obs.select(channel="U")[0] + v = __get_obs_v_from_obs(obs) + w = obs.select(channel="W") f = obs.select(channel="F") - obs_h = h.data - obs_e = e.data + obs_u = u.data + obs_v = v.data d0 = ChannelConverter.get_radians_from_minutes( - numpy.float64(e.stats.declination_base) / 10 + numpy.float64(v.stats.declination_base) / 10 ) - (mag_h, mag_d) = ChannelConverter.get_mag_from_obs(obs_h, obs_e, d0) + (mag_h, mag_d) = ChannelConverter.get_mag_from_obs(obs_u, obs_v, d0) return ( obspy.core.Stream( - (__get_trace("H", h.stats, mag_h), __get_trace("D", e.stats, mag_d)) + (__get_trace("H", u.stats, mag_h), __get_trace("D", v.stats, mag_d)) ) - + z + + w + f ) @@ -193,7 +193,7 @@ def get_obs_from_mag(mag, include_d=False): Returns ------- obspy.core.Stream - new stream object containing observatory components H, D, E, Z, and F + new stream object containing observatory components U, D, V, W, and F """ h = mag.select(channel="H")[0] d = mag.select(channel="D")[0] @@ -205,43 +205,43 @@ def get_obs_from_mag(mag, include_d=False): d0 = ChannelConverter.get_radians_from_minutes( numpy.float64(d.stats.declination_base) / 10 ) - (obs_h, obs_e) = ChannelConverter.get_obs_from_mag(mag_h, mag_d, d0) + (obs_u, obs_v) = ChannelConverter.get_obs_from_mag(mag_h, mag_d, d0) - traces = (__get_trace("H", h.stats, obs_h), __get_trace("E", d.stats, obs_e)) + traces = (__get_trace("U", h.stats, obs_u), __get_trace("V", d.stats, obs_v)) if include_d: - obs_d = ChannelConverter.get_obs_d_from_obs(obs_h, obs_e) + obs_d = ChannelConverter.get_obs_d_from_obs(obs_u, obs_v) traces = traces + (__get_trace("D", d.stats, obs_d),) return obspy.core.Stream(traces) + z + f -def get_obs_from_obs(obs, include_e=False, include_d=False): +def get_obs_from_obs(obs, include_v=False, include_d=False): """Fill in the observatory parameters as requested Parameters ---------- stream: obspy.core.Stream - stream containing the observatory components H, D or E, Z, and F. + stream containing the observatory components U, D or V, W, and F. include_e: boolean - whether to include the e component + whether to include the v component include_d: boolean whether to include the d component Returns ------- obspy.core.Stream - new stream object containing observatory components H, D, E, Z, and F + new stream object containing observatory components U, D, V, W, and F """ - h = obs.select(channel="H")[0] - z = obs.select(channel="Z") + u = obs.select(channel="U")[0] + w = obs.select(channel="W") f = obs.select(channel="F") - traces = (h,) + traces = (u,) if include_d: d = __get_obs_d_from_obs(obs) traces = traces + (d,) - if include_e: - e = __get_obs_e_from_obs(obs) - traces = traces + (e,) - return obspy.core.Stream(traces) + z + f + if include_v: + v = __get_obs_v_from_obs(obs) + traces = traces + (v,) + return obspy.core.Stream(traces) + w + f def __get_trace(channel, stats, data): @@ -269,12 +269,12 @@ def __get_trace(channel, stats, data): def __get_obs_d_from_obs(obs): """Get trace containing observatory D component. - Returns D if found, otherwise computes D from H, E, D0. + Returns D if found, otherwise computes D from U, V, D0. Parameters ---------- obs : obspy.core.Stream - observatory components (D) or (H, E). + observatory components (D) or (U, V). Returns ------- @@ -284,35 +284,35 @@ def __get_obs_d_from_obs(obs): try: d = obs.select(channel="D")[0] except IndexError: - h = obs.select(channel="H")[0] - e = obs.select(channel="E")[0] + u = obs.select(channel="U")[0] + v = obs.select(channel="V")[0] d = __get_trace( - "D", e.stats, ChannelConverter.get_obs_d_from_obs(h.data, e.data) + "D", v.stats, ChannelConverter.get_obs_d_from_obs(u.data, v.data) ) return d -def __get_obs_e_from_obs(obs): - """Get trace containing observatory E component. +def __get_obs_v_from_obs(obs): + """Get trace containing observatory V component. - Returns E if found, otherwise computes E from H,D. + Returns V if found, otherwise computes V from U,D. Parameters ---------- obs : obspy.core.Stream - observatory components (E) or (H, D). + observatory components (V) or (U, D). Returns ------- obspy.core.Trace - observatory component E. + observatory component V. """ try: - e = obs.select(channel="E")[0] + v = obs.select(channel="V")[0] except IndexError: - h = obs.select(channel="H")[0] + u = obs.select(channel="U")[0] d = obs.select(channel="D")[0] - e = __get_trace( - "E", d.stats, ChannelConverter.get_obs_e_from_obs(h.data, d.data) + v = __get_trace( + "V", d.stats, ChannelConverter.get_obs_v_from_obs(u.data, d.data) ) - return e + return v diff --git a/geomagio/TimeseriesUtility.py b/geomagio/TimeseriesUtility.py index e0729c21b81796707a06cff1184765aeab5be29c..f5aa9856064eeb71b3d6bd19eeea24b4925b819e 100644 --- a/geomagio/TimeseriesUtility.py +++ b/geomagio/TimeseriesUtility.py @@ -610,6 +610,8 @@ def split_trace(trace: Trace, size: int = 86400) -> Stream: size=size, trim=True, ): + if interval["start"] == interval["end"]: + return Stream([out_trace]) stream += out_trace.slice( starttime=interval["start"], endtime=interval["end"] - out_trace.stats.delta, diff --git a/geomagio/adjusted/AdjustedMatrix.py b/geomagio/adjusted/AdjustedMatrix.py index 88e7169bff4200f65eb1899cfa89077afbafab5b..f02671ae2161d2e751b758b13cead236f97e73e1 100644 --- a/geomagio/adjusted/AdjustedMatrix.py +++ b/geomagio/adjusted/AdjustedMatrix.py @@ -32,7 +32,7 @@ class AdjustedMatrix(BaseModel): def process( self, stream: Stream, - inchannels=["H", "E", "Z", "F"], + inchannels=["U", "V", "W", "F"], outchannels=["X", "Y", "Z", "F"], ): """ Apply matrix to raw data. Apply pier correction to F when necessary """ diff --git a/geomagio/algorithm/AdjustedAlgorithm.py b/geomagio/algorithm/AdjustedAlgorithm.py index fcbe2dcebb8e66e2d95e9235a7134e905f52eca6..ef92e2ed471e8b7e767f28b0a23a6377961b2065 100644 --- a/geomagio/algorithm/AdjustedAlgorithm.py +++ b/geomagio/algorithm/AdjustedAlgorithm.py @@ -23,7 +23,7 @@ class AdjustedAlgorithm(Algorithm): inchannels=None, outchannels=None, ): - inchannels = inchannels or ["H", "E", "Z", "F"] + inchannels = inchannels or ["U", "V", "W", "F"] outchannels = outchannels or ["X", "Y", "Z", "F"] Algorithm.__init__( self, diff --git a/geomagio/algorithm/DeltaFAlgorithm.py b/geomagio/algorithm/DeltaFAlgorithm.py index 22ebab00988a260a6fc986048ef076caa5b2ad2a..bea31af9d77271fe16d39a00fcd63a99327ab5e0 100644 --- a/geomagio/algorithm/DeltaFAlgorithm.py +++ b/geomagio/algorithm/DeltaFAlgorithm.py @@ -10,10 +10,10 @@ from .. import StreamConverter # List of channels by geomagnetic observatory orientation. # geo represents a geographic north/south orientation # obs represents the sensor orientation aligned close to the mag orientation -# obsd is the same as obs, but with D(declination) instead of E (e/w vector) +# obsd is the same as obs, but with D(declination) instead of V (e/w vector) CHANNELS = { "geo": ["X", "Y", "Z", "F"], - "obs": ["H", "E", "Z", "F"], + "obs": ["U", "V", "W", "F"], "obsd": ["H", "D", "Z", "F"], } diff --git a/geomagio/algorithm/FilterAlgorithm.py b/geomagio/algorithm/FilterAlgorithm.py index da0f2df18f115f7be5d9e3d25c86147917a65e4a..861d127c944e6401fe10cb4077a5de8e6c88b125 100644 --- a/geomagio/algorithm/FilterAlgorithm.py +++ b/geomagio/algorithm/FilterAlgorithm.py @@ -411,8 +411,8 @@ class FilterAlgorithm(Algorithm): steps = self.get_filter_steps() # calculate start/end from inverted step array for step in reversed(steps): - start_interval = get_nearest_time(step=step, output_time=start, left=False) - end_interval = get_nearest_time(step=step, output_time=end, left=True) + start_interval = get_nearest_time(step=step, output_time=start, left=True) + end_interval = get_nearest_time(step=step, output_time=end, left=False) start, end = start_interval["data_start"], end_interval["data_end"] return (start, end) diff --git a/geomagio/algorithm/XYZAlgorithm.py b/geomagio/algorithm/XYZAlgorithm.py index 1f43c87853c8da21d7a4636ad1bf7560f35e5471..7c66bc07cd67844e03c739f50b620f6b609b60dd 100644 --- a/geomagio/algorithm/XYZAlgorithm.py +++ b/geomagio/algorithm/XYZAlgorithm.py @@ -12,11 +12,11 @@ from .. import StreamConverter # geo represents a geographic north/south orientation # mag represents the (calculated)instantaneous mangnetic north orientation # obs represents the sensor orientation aligned close to the mag orientation -# obsd is the same as obs, but with D(declination) instead of E (e/w vector) +# obsd is the same as obs, but with D(declination) instead of V (e/w vector) CHANNELS = { "geo": ["X", "Y", "Z", "F"], "mag": ["H", "D", "Z", "F"], - "obs": ["H", "E", "Z", "F"], + "obs": ["U", "V", "W", "F"], "obsd": ["H", "D", "Z", "F"], } diff --git a/geomagio/edge/EdgeFactory.py b/geomagio/edge/EdgeFactory.py index e0f1091c59cab35a47b07ed2b5150641cf847440..686466f88ad62ff0f0ffa46ed86981e7cf9306c7 100644 --- a/geomagio/edge/EdgeFactory.py +++ b/geomagio/edge/EdgeFactory.py @@ -199,6 +199,11 @@ class EdgeFactory(TimeseriesFactory): channel and that trace should have an ndarray, with nan's representing gaps. """ + if not TimeseriesUtility.has_any_channels( + stream=timeseries, channels=channels, starttime=starttime, endtime=endtime + ): + sys.stderr.write("No data to write\n") + return stats = timeseries[0].stats observatory = observatory or stats.station or self.observatory channels = channels or self.channels @@ -308,13 +313,13 @@ class EdgeFactory(TimeseriesFactory): if channel == "D": edge_channel = edge_interval_code + "VD" - elif channel == "E": + elif channel in ["E", "V"]: edge_channel = edge_interval_code + "VE" elif channel == "F": edge_channel = edge_interval_code + "SF" - elif channel == "H": + elif channel in ["H", "U"]: edge_channel = edge_interval_code + "VH" - elif channel == "Z": + elif channel in ["Z", "W"]: edge_channel = edge_interval_code + "VZ" elif channel == "G": edge_channel = edge_interval_code + "SG" diff --git a/geomagio/edge/MiniSeedFactory.py b/geomagio/edge/MiniSeedFactory.py index 99c3b9eec31e63a125131b6c0f65933220b13822..eb1397f2e15f4845fe945d2d129f574a1249c80b 100644 --- a/geomagio/edge/MiniSeedFactory.py +++ b/geomagio/edge/MiniSeedFactory.py @@ -67,7 +67,7 @@ class MiniSeedFactory(TimeseriesFactory): self, host="cwbpub.cr.usgs.gov", port=2061, - write_port=7981, + write_port=7905, observatory=None, channels=None, type=None, @@ -190,6 +190,11 @@ class MiniSeedFactory(TimeseriesFactory): channel and that trace should have an ndarray, with nan's representing gaps. """ + if not TimeseriesUtility.has_any_channels( + stream=timeseries, channels=channels, starttime=starttime, endtime=endtime + ): + sys.stderr.write("No data to write\n") + return stats = timeseries[0].stats observatory = observatory or stats.station or self.observatory channels = channels or self.channels diff --git a/geomagio/edge/MiniSeedInputClient.py b/geomagio/edge/MiniSeedInputClient.py index a25d31ce89741d8483aa9a1bf55220b1d2c3358e..d2dc2e148e6bb8351b846bc2ccca4d268a544a35 100644 --- a/geomagio/edge/MiniSeedInputClient.py +++ b/geomagio/edge/MiniSeedInputClient.py @@ -25,7 +25,7 @@ class MiniSeedInputClient(object): Floating point precision for output data """ - def __init__(self, host, port=2061, encoding="float32"): + def __init__(self, host, port=2061, encoding="float64"): self.host = host self.port = port self.encoding = encoding diff --git a/geomagio/processing/__init__.py b/geomagio/processing/__init__.py index be97cfbd5e32485df54fc814fd646c595685fed7..b395a8b0beccb9c28df42b2be3b30d61c8083013 100644 --- a/geomagio/processing/__init__.py +++ b/geomagio/processing/__init__.py @@ -4,8 +4,14 @@ Note that these implementations are subject to change, and should be considered less stable than other packages in the library. """ from .factory import get_edge_factory, get_miniseed_factory -from .observatory import adjusted, average, deltaf, rotate, sqdist_minute -from .obsrio import obsrio_minute, obsrio_second, obsrio_temperatures, obsrio_tenhertz +from .derived import adjusted, average, deltaf, rotate, sqdist_minute +from .obsrio import ( + filter_day, + filter_hour, + filter_minute, + filter_temperatures, + filter_tenhertz, +) __all__ = [ @@ -14,10 +20,11 @@ __all__ = [ "deltaf", "get_edge_factory", "get_miniseed_factory", - "obsrio_minute", - "obsrio_second", - "obsrio_temperatures", - "obsrio_tenhertz", + "filter_day", + "filter_hour", + "filter_minute", + "filter_temperatures", + "filter_tenhertz", "rotate", "sqdist_minute", ] diff --git a/geomagio/processing/derived.py b/geomagio/processing/derived.py new file mode 100644 index 0000000000000000000000000000000000000000..3fbf24b77e4091dc864c7421ab1cad9cfeee06fb --- /dev/null +++ b/geomagio/processing/derived.py @@ -0,0 +1,319 @@ +from typing import List, Literal, Optional + +from obspy import UTCDateTime + +from ..adjusted import AdjustedMatrix +from ..algorithm import ( + AdjustedAlgorithm, + AverageAlgorithm, + DeltaFAlgorithm, + SqDistAlgorithm, + XYZAlgorithm, +) +from ..Controller import Controller, get_realtime_interval +from ..metadata import MetadataCategory, MetadataFactory, MetadataQuery +from ..TimeseriesFactory import TimeseriesFactory +from .factory import get_miniseed_factory + + +def adjusted( + observatory: str, + input_factory: Optional[TimeseriesFactory] = None, + output_factory: Optional[TimeseriesFactory] = None, + realtime_interval: int = 600, + update_limit: int = 10, +): + """Run Adjusted algorithm. + + Parameters + ---------- + observatory: observatory to calculate + input_factory: where to read, should be configured with data_type + output_factory: where to write, should be configured with data_type + realtime_interval: window in seconds + + Uses update_limit=10. + """ + starttime, endtime = get_realtime_interval(realtime_interval) + controller = Controller( + algorithm=AdjustedAlgorithm( + matrix=get_adjusted_matrix(observatory=observatory, time=endtime), + data_type="adjusted", + location="A0", + ), + inputFactory=input_factory or get_miniseed_factory(data_type="variation"), + inputInterval="second", + outputFactory=output_factory or get_miniseed_factory(data_type="adjusted"), + outputInterval="second", + ) + controller.run_as_update( + observatory=(observatory,), + output_observatory=(observatory,), + starttime=starttime, + endtime=endtime, + input_channels=("U", "V", "W", "F"), + output_channels=("X", "Y", "Z", "F"), + realtime=realtime_interval, + update_limit=update_limit, + ) + + +def average( + observatories: List[str], + input_channel: str, + input_factory: Optional[TimeseriesFactory] = None, + output_channel: Optional[str] = None, + output_factory: Optional[TimeseriesFactory] = None, + output_observatory: str = "USGS", + realtime_interval: int = 600, +): + """Run Average algorithm. + + Parameters + ---------- + observatories: input observatories to calculate + input_channel: channel from multiple observatories to average + input_factory: where to read, should be configured with data_type and interval + interval: data interval + output_channel: channel to write (defaults to input_channel). + output_factory: where to write, should be configured with data_type and interval + output_observatory: observatory where output is written + realtime_interval: window in seconds + + Uses update_limit=10. + """ + starttime, endtime = get_realtime_interval(realtime_interval) + controller = Controller( + algorithm=AverageAlgorithm(observatories=observatories, channel=output_channel), + inputFactory=input_factory or get_miniseed_factory(data_type="variation"), + inputInterval="minute", + outputFactory=output_factory or get_miniseed_factory(data_type="variation"), + outputInterval="minute", + ) + controller.run_as_update( + observatory=observatories, + output_observatory=(output_observatory,), + starttime=starttime, + endtime=endtime, + output_channels=(output_channel or input_channel,), + realtime=realtime_interval, + update_limit=10, + ) + + +def deltaf( + observatory: str, + data_type: Literal["adjusted", "variation"], + interval: str, + input_factory: Optional[TimeseriesFactory] = None, + output_factory: Optional[TimeseriesFactory] = None, + deltaf_from="obs", + realtime_interval: int = 600, + update_limit: int = 10, +): + """Run Delta-F algorithm. + + Parameters + ---------- + observatory: observatory to calculate + data_type: factory data type + interval: data interval + input_factory: where to read, should be configured with data_type and interval + output_factory: where to write, should be configured with data_type and interval + deltaf_from: one of {"obs", "mag", "geo"} + realtime_interval: window in seconds + + Uses update_limit=10. + """ + starttime, endtime = get_realtime_interval(realtime_interval) + controller = Controller( + algorithm=DeltaFAlgorithm(informat=deltaf_from), + inputFactory=input_factory or get_miniseed_factory(data_type=data_type), + inputInterval=interval, + outputFactory=output_factory or get_miniseed_factory(data_type=data_type), + outputInterval=interval, + ) + controller.run_as_update( + observatory=(observatory,), + output_observatory=(observatory,), + starttime=starttime, + endtime=endtime, + output_channels=("G",), + realtime=realtime_interval, + update_limit=update_limit, + ) + + +def get_adjusted_matrix(observatory: str, time: UTCDateTime) -> AdjustedMatrix: + """gets most recent valid adjusted matrix(within past month)""" + query = MetadataQuery( + station=observatory, + category=MetadataCategory.ADJUSTED_MATRIX, + created_time=time - (86400 * 31), + ) + metas = MetadataFactory().get_metadata(query=query) + try: + return AdjustedMatrix(**metas[-1].metadata) + except: + raise ValueError("No valid adjusted matrix found") + + +def process_adjusted( + observatory: str, + interval: str, + realtime_interval: int = 600, + update_limit: int = 10, +): + """compute 1 second/minute adjusted variation channels""" + rotate( + observatory=observatory, + data_type="adjusted", + interval=interval, + output_channels=("H", "D"), + xyz_from="geo", + xyz_to="mag", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + deltaf( + observatory=observatory, + data_type="adjusted", + deltaf_from="geo", + interval=interval, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + + +def process_variation( + observatory: str, + interval: str, + realtime_interval: int = 600, + update_limit: int = 10, +): + """compute 1 second/minute derived variation channels""" + rotate( + observatory=observatory, + data_type="variation", + interval=interval, + xyz_from="obs", + xyz_to="geo", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + rotate( + observatory=observatory, + data_type="variation", + interval=interval, + output_channels=("D",), + xyz_from="obs", + xyz_to="obsd", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + deltaf( + observatory=observatory, + interval=interval, + data_type="variation", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + + +def rotate( + observatory: str, + data_type: Literal["adjusted", "variation"], + interval: str, + input_factory: Optional[TimeseriesFactory] = None, + output_channels=("X", "Y"), + output_factory: Optional[TimeseriesFactory] = None, + xyz_from="obs", + xyz_to="geo", + realtime_interval: int = 600, + update_limit: int = 10, +): + """Run XYZ rotation algorithm. + + Parameters + ---------- + observatory: observatory to calculate + data_type: factory data type + interval: data interval + input_factory: where to read, should be configured with data_type and interval + output_channels: which channels to write + output_factory: where to write, should be configured with data_type and interval + realtime_interval: window in seconds + xyz_from: one of {"obs", "mag", "geo"} + xyz_to: one of {"obs", "obsd", "mag", "geo"} + + Uses update_limit=10. + """ + starttime, endtime = get_realtime_interval(realtime_interval) + controller = Controller( + algorithm=XYZAlgorithm(informat=xyz_from, outformat=xyz_to), + inputFactory=input_factory or get_miniseed_factory(data_type=data_type), + inputInterval=interval, + outputFactory=output_factory or get_miniseed_factory(data_type=data_type), + outputInterval=interval, + ) + controller.run_as_update( + observatory=(observatory,), + output_observatory=(observatory,), + starttime=starttime, + endtime=endtime, + output_channels=output_channels, + realtime=realtime_interval, + update_limit=update_limit, + ) + + +def sqdist_minute( + observatory: str, + data_type: Literal["adjusted", "variation"], + statefile: str, + input_factory: Optional[TimeseriesFactory] = None, + output_factory: Optional[TimeseriesFactory] = None, + realtime_interval: int = 1800, +): + """Run SqDist algorithm. + + Only supports "minute" interval. + + Parameters + ---------- + observatory: observatory to calculate + data_type: factory data type + statefile: sqdist statefile must already exist + input_factory: where to read, should be configured with data_type and interval + output_factory: where to write, should be configured with data_type and interval + realtime_interval: window in seconds + """ + if not statefile: + raise ValueError("Statefile is required.") + if realtime_interval < 1800: + realtime_interval = 1800 + starttime, endtime = get_realtime_interval(realtime_interval) + controller = Controller( + algorithm=SqDistAlgorithm( + alpha=2.3148e-5, + gamma=3.3333e-2, + m=1440, + mag=True, + smooth=180, + beta=0, + statefile=statefile, + ), + inputFactory=input_factory or get_miniseed_factory(data_type=data_type), + inputInterval="minute", + outputFactory=output_factory or get_miniseed_factory(data_type=data_type), + outputInterval="minute", + ) + # sqdist is stateful, use run + controller.run( + observatory=(observatory,), + starttime=starttime, + endtime=endtime, + input_channels=("X", "Y", "Z", "F"), + output_channels=("H_SQ", "H_SV", "H_Dist"), + realtime=realtime_interval, + ) diff --git a/geomagio/processing/factory.py b/geomagio/processing/factory.py index d9a065497d9cf6b0a38c391355e11a9d698795d2..1838cd74c756dd9b9fae54fe0bffd99c2c17077c 100644 --- a/geomagio/processing/factory.py +++ b/geomagio/processing/factory.py @@ -19,7 +19,6 @@ def get_miniseed_factory( data_type="variation", interval="second", **kwargs ) -> TimeseriesFactory: return MiniSeedFactory( - convert_channels=("U", "V", "W"), host=os.getenv("EDGE_HOST", "127.0.0.1"), interval=interval, type=data_type, diff --git a/geomagio/processing/observatory.py b/geomagio/processing/observatory.py index 85a9cfd7f033c4e72bb3401456f939c4e154a8c1..fd579277f840f6d5d1862f5e7536bcb958e5b36b 100644 --- a/geomagio/processing/observatory.py +++ b/geomagio/processing/observatory.py @@ -1,243 +1,225 @@ -from typing import List, Optional +from enum import Enum -import numpy +import typer -from ..algorithm import ( - AdjustedAlgorithm, - AverageAlgorithm, - DeltaFAlgorithm, - SqDistAlgorithm, - XYZAlgorithm, +from . import derived +from . import obsrio +from . import pcdcp + +app = typer.Typer( + help=f""" + Command line interface for processing pipeline + """ ) -from ..Controller import Controller, get_realtime_interval -from ..TimeseriesFactory import TimeseriesFactory -from .factory import get_edge_factory -def adjusted( +class DataFormat(str, Enum): + OBSRIO = "obsrio" + PCDCP = "pcdcp" + + +class DataType(str, Enum): + ADJUSTED = "adjusted" + VARIATION = "variation" + + +def main(): + app() + + +@app.command( + name="adjusted", + help=f""" + transforms, filters, and derives data at 1Hz and 1 min. + + Applies adjusted algorithm at 1Hz: U,V,W,F -> X,Y,Z,F + + Dervies 1Hz adjusted channels: X,Y,H,D,G + + Filters 1Hz adjusted to 1 min adjusted + + Dervies 1 min adjusted channels: X,Y,H,D,G + + Applies SQDistAlgorithm to 1 min adjused: H_SQ, H_SV, H_Dist + """, +) +def process_adjusted( observatory: str, - input_factory: Optional[TimeseriesFactory] = None, - interval: str = "second", - output_factory: Optional[TimeseriesFactory] = None, - matrix: Optional[numpy.ndarray] = None, - pier_correction: Optional[float] = None, - statefile: Optional[str] = None, + sqdist_statefile: str, realtime_interval: int = 600, + update_limit: int = 10, ): - """Run Adjusted algorithm. - - Parameters - ---------- - observatory: observatory to calculate - input_factory: where to read, should be configured with data_type - interval: data interval - output_factory: where to write, should be configured with data_type - matrix: adjusted matrix - pier_correction: adjusted pier correction - statefile: adjusted statefile - realtime_interval: window in seconds - - Uses update_limit=10. - """ - if not statefile and (not matrix or not pier_correction): - raise ValueError("Either statefile or matrix and pier_correction are required.") - starttime, endtime = get_realtime_interval(realtime_interval) - controller = Controller( - algorithm=AdjustedAlgorithm( - matrix=matrix, - pier_correction=pier_correction, - statefile=statefile, - data_type="adjusted", - location="A0", - ), - inputFactory=input_factory or get_edge_factory(data_type="variation"), - inputInterval=interval, - outputFactory=output_factory or get_edge_factory(data_type="adjusted"), - outputInterval=interval, + derived.adjusted( + observatory=observatory, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + derived.process_adjusted( + observatory=observatory, + interval="second", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + obsrio.filter_minute( + observatory=observatory, + data_type="adjusted", + channels=["X", "Y", "Z", "F"], + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + derived.process_adjusted( + observatory=observatory, + interval="minute", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + derived.sqdist_minute( + observatory=observatory, + data_type="adjusted", + statefile=sqdist_statefile, + realtime_interval=realtime_interval, ) - controller.run_as_update( - observatory=(observatory,), - output_observatory=(observatory,), - starttime=starttime, - endtime=endtime, - input_channels=("H", "E", "Z", "F"), - output_channels=("X", "Y", "Z", "F"), - realtime=realtime_interval, - update_limit=10, + pcdcp.legacy( + observatory=observatory, + data_type="adjusted", + realtime_interval=realtime_interval, + update_limit=update_limit, ) -def average( - observatories: List[str], - input_channel: str, - input_factory: Optional[TimeseriesFactory] = None, - interval: str = "second", - output_channel: str = None, - output_factory: Optional[TimeseriesFactory] = None, - output_observatory: str = "USGS", - realtime_interval: int = 600, +@app.command( + name="obsrio", + help=f""" + filters and derives variation/adjusted data at 1 hour/day. + + Filters 1 min to 1 hour/day + + Dervies 1 hour/day derived channels: X,Y,H(adjusted),D,G + """, +) +def process_obsrio( + observatory: str, + data_type: str, + realtime_interval: int = 86400, + update_limit: int = 7, ): - """Run Average algorithm. - - Parameters - ---------- - observatories: input observatories to calculate - input_channel: channel from multiple observatories to average - input_factory: where to read, should be configured with data_type and interval - interval: data interval - output_channel: channel to write (defaults to input_channel). - output_factory: where to write, should be configured with data_type and interval - output_observatory: observatory where output is written - realtime_interval: window in seconds - - Uses update_limit=10. - """ - starttime, endtime = get_realtime_interval(realtime_interval) - controller = Controller( - algorithm=AverageAlgorithm(observatories=observatories, channel=output_channel), - inputFactory=input_factory or get_edge_factory(), - inputInterval=interval, - outputFactory=output_factory or get_edge_factory(), - outputInterval=interval, + channels = ( + ("X", "Y", "Z", "F") if data_type == "adjusted" else ("U", "V", "W", "Z", "F") ) - controller.run_as_update( - observatory=observatories, - output_observatory=(output_observatory,), - starttime=starttime, - endtime=endtime, - output_channels=(output_channel or input_channel,), - realtime=realtime_interval, - update_limit=10, + obsrio.filter_day( + observatory=observatory, + data_type=data_type, + channels=channels, ) + obsrio.filter_hour( + observatory=observatory, + data_type=data_type, + channels=channels, + ) + if data_type == DataType.ADJUSTED: + derived.process_adjusted( + observatory=observatory, + interval="hour", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + derived.process_adjusted( + observatory=observatory, + interval="day", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + elif data_type == DataType.VARIATION: + derived.process_variation( + observatory=observatory, + interval="hour", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + derived.process_variation( + observatory=observatory, + interval="day", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) -def deltaf( - observatory: str, - input_factory: Optional[TimeseriesFactory] = None, - interval: str = "second", - output_factory: Optional[TimeseriesFactory] = None, - deltaf_from="obs", - realtime_interval: int = 600, -): - """Run Delta-F algorithm. +@app.command( + name="variation", + help=f""" + filters and derives variation channels at 1Hz and 1min. - Parameters - ---------- - observatory: observatory to calculate - input_factory: where to read, should be configured with data_type and interval - output_factory: where to write, should be configured with data_type and interval - deltaf_from: one of {"obs", "mag", "geo"} - realtime_interval: window in seconds + Gathers 1Hz variation data from obrio/pcdcp: + + pcdcp: + + copy edge channels to miniseed: H,E,Z,F,UK1-4 -> U,V,W,F,UK1-4 + + obsrio: + + filter 10Hz miniseed to 1Hz miniseed + + filter 1Hz temperatures to 1 min temperatures: LK1-4 -> UK1-4 + + copy 1 min temperatures from miniseed to edge - Uses update_limit=10. - """ - starttime, endtime = get_realtime_interval(realtime_interval) - controller = Controller( - algorithm=DeltaFAlgorithm(informat=deltaf_from), - inputFactory=input_factory or get_edge_factory(), - inputInterval=interval, - outputFactory=output_factory or get_edge_factory(), - outputInterval=interval, - ) - controller.run_as_update( - observatory=(observatory,), - output_observatory=(observatory,), - starttime=starttime, - endtime=endtime, - output_channels=("G",), - realtime=realtime_interval, - update_limit=10, - ) + Dervies 1Hz variation channels: X,Y,D,G -def rotate( + Filters 1Hz variation to 1 min variation + + Dervies 1 min variation channels: X,Y,D,G + + Applies SQDistAlgorithm to 1 min variation: H_SQ, H_SV, H_Dist + """, +) +def process_variation( observatory: str, - input_factory: Optional[TimeseriesFactory] = None, - interval: str = "second", - output_channels=("X", "Y"), - output_factory: Optional[TimeseriesFactory] = None, + data_format: DataFormat, + sqdist_statefile: str, realtime_interval: int = 600, - xyz_from="obs", - xyz_to="geo", + update_limit: int = 10, ): - """Run XYZ rotation algorithm. - - Parameters - ---------- - observatory: observatory to calculate - input_factory: where to read, should be configured with data_type and interval - output_channels: which channels to write - output_factory: where to write, should be configured with data_type and interval - realtime_interval: window in seconds - xyz_from: one of {"obs", "mag", "geo"} - xyz_to: one of {"obs", "obsd", "mag", "geo"} - - Uses update_limit=10. - """ - starttime, endtime = get_realtime_interval(realtime_interval) - controller = Controller( - algorithm=XYZAlgorithm(informat=xyz_from, outformat=xyz_to), - inputFactory=input_factory or get_edge_factory(), - inputInterval=interval, - outputFactory=output_factory or get_edge_factory(), - outputInterval=interval, + if data_format == DataFormat.OBSRIO: + obsrio.prepare( + observatory=observatory, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + elif data_format == DataFormat.PCDCP: + pcdcp.prepare( + observatory=observatory, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + derived.process_variation( + observatory=observatory, + interval="second", + realtime_interval=realtime_interval, + update_limit=update_limit, ) - controller.run_as_update( - observatory=(observatory,), - output_observatory=(observatory,), - starttime=starttime, - endtime=endtime, - output_channels=output_channels, - realtime=realtime_interval, - update_limit=10, + obsrio.filter_minute( + observatory=observatory, + data_type="variation", + channels=["U", "V", "W", "Z", "F"], + realtime_interval=realtime_interval, + update_limit=update_limit, ) - - -def sqdist_minute( - observatory: str, - statefile: str, - input_factory: Optional[TimeseriesFactory] = None, - output_factory: Optional[TimeseriesFactory] = None, - realtime_interval: int = 1800, -): - """Run SqDist algorithm. - - Only supports "minute" interval. - - Parameters - ---------- - observatory: observatory to calculate - statefile: sqdist statefile must already exist - input_factory: where to read, should be configured with data_type and interval - output_factory: where to write, should be configured with data_type and interval - realtime_interval: window in seconds - """ - if not statefile: - raise ValueError("Statefile is required.") - starttime, endtime = get_realtime_interval(realtime_interval) - controller = Controller( - algorithm=SqDistAlgorithm( - alpha=2.3148e-5, - gamma=3.3333e-2, - m=1440, - mag=True, - smooth=180, - statefile=statefile, - ), - inputFactory=input_factory or get_edge_factory(interval="minute"), - inputInterval="minute", - outputFactory=output_factory or get_edge_factory(interval="minute"), - outputInterval="minute", + derived.process_variation( + observatory=observatory, + interval="minute", + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + derived.sqdist_minute( + observatory=observatory, + data_type="variation", + statefile=sqdist_statefile, + realtime_interval=realtime_interval, ) - # sqdist is stateful, use run - controller.run( - observatory=(observatory,), - output_observatory=(observatory,), - starttime=starttime, - endtime=endtime, - input_channels=("X", "Y", "Z", "F"), - output_channels=("MDT", "MSQ", "MSV"), - realtime=realtime_interval, - rename_output_channel=(("H_Dist", "MDT"), ("H_SQ", "MSQ"), ("H_SV", "MSV")), - update_limit=10, + pcdcp.legacy( + observatory=observatory, + data_type="variation", + realtime_interval=realtime_interval, + update_limit=update_limit, ) diff --git a/geomagio/processing/obsrio.py b/geomagio/processing/obsrio.py index bf0acf2b81687c6a3f590e6b4cd8b902f4730aa3..d0019418531390c281e87a358de67b51e297d761 100644 --- a/geomagio/processing/obsrio.py +++ b/geomagio/processing/obsrio.py @@ -1,228 +1,108 @@ -from typing import Optional +from enum import Enum +from typing import Literal, List, Optional import typer -from ..algorithm import Algorithm, FilterAlgorithm -from ..edge import EdgeFactory, MiniSeedFactory +from ..algorithm import FilterAlgorithm from ..Controller import ( Controller, get_realtime_interval, ) from ..TimeseriesFactory import TimeseriesFactory -from .factory import get_edge_factory, get_miniseed_factory +from .factory import get_miniseed_factory, get_edge_factory +from .pcdcp import copy_channels -def main(): - typer.run(obsrio_filter) - - -def obsrio_filter( - interval: str, - observatory: str, - input_factory: Optional[str] = None, - host: str = "127.0.0.1", - port: str = 2061, - output_factory: Optional[str] = None, - output_port: int = typer.Option( - 2061, help="Port where output factory writes data." - ), - output_read_port: int = typer.Option( - 2061, help="Port where output factory reads data" - ), - realtime_interval: int = 600, - update_limit: int = 10, -): - if interval == "realtime": - filter_realtime( - observatory=observatory, - input_factory=input_factory, - host=host, - port=port, - output_factory=output_factory, - output_port=output_port, - output_read_port=output_read_port, - realtime_interval=realtime_interval, - update_limit=update_limit, - ) - elif interval in ["hour", "day"]: - input_factory = EdgeFactory(host=host, port=port) - output_factory = MiniSeedFactory( - host=host, port=output_read_port, write_port=output_port - ) - if interval == "hour": - obsrio_hour( - observatory=observatory, - input_factory=input_factory, - output_factory=output_factory, - realtime_interval=realtime_interval, - update_limit=update_limit, - ) - elif interval == "day": - obsrio_day( - observatory=observatory, - input_factory=input_factory, - output_factory=output_factory, - realtime_interval=realtime_interval, - update_limit=update_limit, - ) - else: - raise ValueError("Invalid interval") - - -def filter_realtime( - observatory: str, - input_factory: Optional[str] = None, - host: str = "127.0.0.1", - port: str = 2061, - output_factory: Optional[str] = None, - output_port: int = typer.Option( - 2061, help="Port where output factory writes data." - ), - output_read_port: int = typer.Option( - 2061, help="Port where output factory reads data" - ), - realtime_interval: int = 600, - update_limit: int = 10, -): - """Filter 10Hz miniseed, 1 second, one minute, and temperature data. - Defaults set for realtime processing; can also be implemented to update legacy data""" - if input_factory == "miniseed": - input_factory = MiniSeedFactory(host=host, port=port) - elif input_factory == "edge": - input_factory = EdgeFactory(host=host, port=port) - if output_factory == "miniseed": - output_factory = MiniSeedFactory( - host=host, port=output_read_port, write_port=output_port - ) - elif output_factory == "edge": - output_factory = EdgeFactory( - host=host, port=output_read_port, write_port=output_port - ) - - obsrio_tenhertz( - observatory=observatory, - input_factory=input_factory, - output_factory=output_factory, - realtime_interval=realtime_interval, - update_limit=update_limit, - ) - obsrio_second( - observatory=observatory, - input_factory=input_factory, - output_factory=output_factory, - realtime_interval=realtime_interval, - update_limit=update_limit, - ) - obsrio_minute( - observatory=observatory, - input_factory=input_factory, - output_factory=output_factory, - realtime_interval=realtime_interval, - update_limit=update_limit, - ) - obsrio_temperatures( - observatory=observatory, - input_factory=input_factory, - output_factory=output_factory, - realtime_interval=realtime_interval, - update_limit=update_limit, - ) - - -def obsrio_day( +def filter_day( observatory: str, + data_type: Literal["adjusted", "variation"], + channels: List[str], input_factory: Optional[TimeseriesFactory] = None, output_factory: Optional[TimeseriesFactory] = None, realtime_interval: int = 86400, update_limit: int = 7, ): - """Filter 1 second edge H,E,Z,F to 1 day miniseed U,V,W,F.""" + """Filter 1 minute miniseed to 1 day miniseed""" starttime, endtime = get_realtime_interval(realtime_interval) controller = Controller( - inputFactory=input_factory or get_edge_factory(), + inputFactory=input_factory or get_miniseed_factory(data_type=data_type), inputInterval="minute", - outputFactory=output_factory or get_miniseed_factory(), + outputFactory=output_factory or get_miniseed_factory(data_type=data_type), outputInterval="day", ) - renames = {"H": "U", "E": "V", "Z": "W", "F": "F"} - for input_channel in renames.keys(): - output_channel = renames[input_channel] + for channel in channels: controller.run_as_update( algorithm=FilterAlgorithm( input_sample_period=60.0, output_sample_period=86400.0, - inchannels=(input_channel,), - outchannels=(output_channel,), + inchannels=(channel,), + outchannels=(channel,), ), observatory=(observatory,), output_observatory=(observatory,), starttime=starttime, endtime=endtime, - input_channels=(input_channel,), - output_channels=(output_channel,), + input_channels=(channel,), + output_channels=(channel,), realtime=realtime_interval, - rename_output_channel=((input_channel, output_channel),), update_limit=update_limit, ) -def obsrio_hour( +def filter_hour( observatory: str, + data_type: Literal["adjusted", "variation"], + channels: List[str], input_factory: Optional[TimeseriesFactory] = None, output_factory: Optional[TimeseriesFactory] = None, realtime_interval: int = 600, update_limit: int = 10, ): - """Filter 1 second edge H,E,Z,F to 1 hour miniseed U,V,W,F.""" + """Filter 1 minute miniseed to 1 hour miniseed""" starttime, endtime = get_realtime_interval(realtime_interval) controller = Controller( - inputFactory=input_factory or get_edge_factory(), + inputFactory=input_factory or get_miniseed_factory(data_type=data_type), inputInterval="minute", - outputFactory=output_factory or get_miniseed_factory(), + outputFactory=output_factory or get_miniseed_factory(data_type=data_type), outputInterval="hour", ) - renames = {"H": "U", "E": "V", "Z": "W", "F": "F"} - for input_channel in renames.keys(): - output_channel = renames[input_channel] + for channel in channels: controller.run_as_update( algorithm=FilterAlgorithm( input_sample_period=60.0, output_sample_period=3600.0, - inchannels=(input_channel,), - outchannels=(output_channel,), + inchannels=(channel,), + outchannels=(channel,), ), observatory=(observatory,), output_observatory=(observatory,), starttime=starttime, endtime=endtime, - input_channels=(input_channel,), - output_channels=(output_channel,), + input_channels=(channel,), + output_channels=(channel,), realtime=realtime_interval, - rename_output_channel=((input_channel, output_channel),), update_limit=update_limit, ) -def obsrio_minute( +def filter_minute( observatory: str, + channels: List[str], + data_type: Literal["adjusted", "variation"], input_factory: Optional[TimeseriesFactory] = None, output_factory: Optional[TimeseriesFactory] = None, realtime_interval: int = 600, update_limit: int = 10, ): - """Filter 1Hz legacy H,E,Z,F to 1 minute legacy. - - Should be called after obsrio_second() and obsrio_tenhertz(), - which populate 1Hz legacy H,E,Z,F. - """ + """Filter 1Hz miniseed to 1 minute miniseed""" starttime, endtime = get_realtime_interval(realtime_interval) controller = Controller( - inputFactory=input_factory or get_edge_factory(), + inputFactory=input_factory or get_miniseed_factory(data_type=data_type), inputInterval="second", - outputFactory=output_factory or get_edge_factory(), + outputFactory=output_factory or get_miniseed_factory(data_type=data_type), outputInterval="minute", ) - for channel in ["H", "E", "Z", "F"]: + for channel in channels: controller.run_as_update( algorithm=FilterAlgorithm( input_sample_period=1, @@ -241,45 +121,19 @@ def obsrio_minute( ) -def obsrio_second( +def filter_temperatures( observatory: str, input_factory: Optional[TimeseriesFactory] = None, output_factory: Optional[TimeseriesFactory] = None, realtime_interval: int = 600, update_limit: int = 10, ): - """Copy 1Hz miniseed F to 1Hz legacy F.""" - starttime, endtime = get_realtime_interval(realtime_interval) - controller = Controller( - algorithm=Algorithm(inchannels=("F",), outchannels=("F",)), - inputFactory=input_factory or get_miniseed_factory(), - outputFactory=output_factory or get_edge_factory(), - ) - controller.run_as_update( - observatory=(observatory,), - output_observatory=(observatory,), - starttime=starttime, - endtime=endtime, - input_channels=("F",), - output_channels=("F",), - realtime=realtime_interval, - update_limit=update_limit, - ) - - -def obsrio_temperatures( - observatory: str, - input_factory: Optional[TimeseriesFactory] = None, - output_factory: Optional[TimeseriesFactory] = None, - realtime_interval: int = 600, - update_limit: int = 10, -): - """Filter temperatures 1Hz miniseed (LK1-4) to 1 minute legacy (UK1-4).""" + """Filter temperatures 1Hz miniseed (LK1-4) to 1 minute miniseed (UK1-4).""" starttime, endtime = get_realtime_interval(realtime_interval) controller = Controller( inputFactory=input_factory or get_miniseed_factory(), inputInterval="second", - outputFactory=output_factory or get_edge_factory(), + outputFactory=output_factory or get_miniseed_factory(), outputInterval="minute", ) renames = {"LK1": "UK1", "LK2": "UK2", "LK3": "UK3", "LK4": "UK4"} @@ -304,38 +158,69 @@ def obsrio_temperatures( ) -def obsrio_tenhertz( +def filter_tenhertz( observatory: str, input_factory: Optional[TimeseriesFactory] = None, output_factory: Optional[TimeseriesFactory] = None, realtime_interval: int = 600, update_limit: int = 10, ): - """Filter 10Hz miniseed U,V,W to 1Hz legacy H,E,Z.""" + """Filter 10Hz miniseed U,V,W to 1Hz miniseed U,V,W""" starttime, endtime = get_realtime_interval(realtime_interval) controller = Controller( - inputFactory=input_factory or get_miniseed_factory(), + inputFactory=input_factory + or get_miniseed_factory(convert_channels=("U", "V", "W")), inputInterval="tenhertz", - outputFactory=output_factory or get_edge_factory(), + outputFactory=output_factory or get_miniseed_factory(), outputInterval="second", ) - renames = {"U": "H", "V": "E", "W": "Z"} - for input_channel in renames.keys(): - output_channel = renames[input_channel] + for channel in ["U", "V", "W"]: controller.run_as_update( algorithm=FilterAlgorithm( input_sample_period=0.1, output_sample_period=1, - inchannels=(input_channel,), - outchannels=(output_channel,), + inchannels=(channel,), + outchannels=(channel,), ), observatory=(observatory,), output_observatory=(observatory,), starttime=starttime, endtime=endtime, - input_channels=(input_channel,), - output_channels=(output_channel,), + input_channels=(channel,), + output_channels=(channel,), realtime=realtime_interval, - rename_output_channel=((input_channel, output_channel),), update_limit=update_limit, ) + + +def prepare(observatory: str, realtime_interval: int = 600, update_limit: int = 10): + filter_tenhertz( + observatory=observatory, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + filter_temperatures( + observatory=observatory, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + copy_channels( + observatory=observatory, + input_channels=["UK1", "UK2", "UK3", "UK4"], + output_channels=["UK1", "UK2", "UK3", "UK4"], + interval="minute", + input_factory=get_miniseed_factory(), + output_factory=get_edge_factory(), + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + copy_channels( + observatory=observatory, + input_channels=["W"], + output_channels=["Z"], + interval="second", + input_factory=get_miniseed_factory(), + output_factory=get_miniseed_factory(), + realtime_interval=realtime_interval, + update_limit=update_limit, + ) diff --git a/geomagio/processing/pcdcp.py b/geomagio/processing/pcdcp.py new file mode 100644 index 0000000000000000000000000000000000000000..8374f6d68cd2bdd59a8c5c7b96ff6d083f97ae44 --- /dev/null +++ b/geomagio/processing/pcdcp.py @@ -0,0 +1,141 @@ +from typing import List, Literal, Optional + +from ..algorithm import Algorithm +from ..Controller import Controller, get_realtime_interval +from .. import TimeseriesFactory +from .factory import get_edge_factory, get_miniseed_factory + + +def prepare( + observatory: str, + input_factory: Optional[TimeseriesFactory] = None, + output_factory: Optional[TimeseriesFactory] = None, + realtime_interval: int = 600, + update_limit: int = 10, +): + """Copies 1Hz edge HEZF to 1Hz miniseed UVWF + UK1-4 edge to UK1-4 miniseed""" + input_factory = input_factory or get_edge_factory() + output_factory = output_factory or get_miniseed_factory() + copy_channels( + observatory=observatory, + input_channels=["H", "E", "Z", "F"], + output_channels=["U", "V", "W", "F"], + interval="second", + input_factory=input_factory, + output_factory=output_factory, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + copy_channels( + observatory=observatory, + input_channels=["W"], + output_channels=["Z"], + interval="second", + input_factory=output_factory, + output_factory=output_factory, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + copy_channels( + observatory=observatory, + input_channels=["UK1", "UK2", "UK3", "UK4"], + output_channels=["UK1", "UK2", "UK3", "UK4"], + interval="minute", + input_factory=input_factory, + output_factory=output_factory, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + + +def legacy( + observatory: str, + data_type: Literal["adjusted", "variation"], + realtime_interval: int = 600, + update_limit: int = 10, +): + """copy filtered/derived miniseed channels to edge""" + input_factory = get_miniseed_factory(data_type=data_type) + output_factory = get_edge_factory(data_type=data_type) + seconds_channels = [ + "X", + "Y", + "D", + "G", + ] + minutes_input_channels = [ + "X", + "Y", + "D", + "G", + "H_SQ", + "H_SV", + "H_Dist", + ] + minutes_output_channels = [ + "X", + "Y", + "D", + "G", + "MSQ", + "MSV", + "MDT", + ] + if data_type == "adjusted": + seconds_channels.extend(["H", "F", "Z"]) + minutes_input_channels.extend(["H", "F", "Z"]) + minutes_output_channels.extend(["H", "F", "Z"]) + copy_channels( + observatory=observatory, + input_channels=seconds_channels, + output_channels=seconds_channels, + interval="second", + input_factory=input_factory, + output_factory=output_factory, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + copy_channels( + observatory=observatory, + input_channels=minutes_input_channels, + output_channels=minutes_output_channels, + interval="minute", + input_factory=input_factory, + output_factory=output_factory, + realtime_interval=realtime_interval, + update_limit=update_limit, + ) + + +def copy_channels( + observatory: str, + input_channels: List[str], + output_channels: List[str], + interval: str, + input_factory: TimeseriesFactory, + output_factory: TimeseriesFactory, + realtime_interval: int = 600, + update_limit: int = 10, +): + """Copy channels between edge and miniseed format""" + starttime, endtime = get_realtime_interval(realtime_interval) + controller = Controller( + algorithm=Algorithm(), + inputFactory=input_factory, + outputFactory=output_factory, + inputInterval=interval, + outputInterval=interval, + ) + for input_channel, output_channel in zip(input_channels, output_channels): + controller.run_as_update( + observatory=(observatory,), + output_observatory=(observatory,), + starttime=starttime, + endtime=endtime, + input_channels=(input_channel,), + output_channels=(output_channel,), + rename_output_channel=((input_channel, output_channel),), + realtime=realtime_interval, + update_limit=update_limit, + ) diff --git a/setup.py b/setup.py index 9a9c5ace7e577e308272665250636eeb2e1027af..155431c5fbaabdae618116d07373846b83a9477f 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ setuptools.setup( "generate-matrix=geomagio.processing.adjusted:main", "geomag-metadata=geomagio.metadata.main:main", "magproc-prepfiles=geomagio.processing.magproc:main", - "obsrio-filter=geomagio.processing.obsrio:main", + "observatory=geomagio.processing.observatory:main", ], }, ) diff --git a/test/StreamConverter_test.py b/test/StreamConverter_test.py index 0c8b4207ac380f9d27efb5c526d24f9703dcec78..4421411516715a3bf73662d0dba8c0048550b451 100644 --- a/test/StreamConverter_test.py +++ b/test/StreamConverter_test.py @@ -63,16 +63,16 @@ def test_get_geo_from_obs(): """StreamConverter_test.test_get_geo_from_obs() The observatory stream containing the observatory traces - ''h'', ''d'' or ''e'', ''z'', and ''f'' converts to the geographic + ''u'', ''d'' or ''v'', ''w'', and ''f'' converts to the geographic stream containing the traces ''x'', ''y'', ''z'', and ''f'' """ obs = obspy.core.Stream() - # 1) Call get_geo_from_obs using equal h, e streams with a decbas of 0 + # 1) Call get_geo_from_obs using equal u, v streams with a decbas of 0 # the geographic stream values X, Y will be the same. - obs += __create_trace("H", [1]) - obs += __create_trace("E", [1]) - obs += __create_trace("Z", [1]) + obs += __create_trace("U", [1]) + obs += __create_trace("V", [1]) + obs += __create_trace("W", [1]) obs += __create_trace("F", [1]) geo = StreamConverter.get_geo_from_obs(obs) X = geo.select(channel="X")[0].data @@ -81,13 +81,13 @@ def test_get_geo_from_obs(): assert_almost_equal(Y[0], 1, 9, "Expect Y to almost equal 1", True) # 2) Call get_geo_from_obs using a decbas of 15 degrees, and streams - # with H = [cos(15), cos(30)], and E = [sin(15), sin(30)]. + # with U = [cos(15), cos(30)], and V = [sin(15), sin(30)]. # Expect streams of X = [cos(30), cos(45)] and Y = sin(30), sin(45) obs = obspy.core.Stream() DECBAS = 15 * D2I - obs += __create_trace("H", [cos(15 * D2R), cos(30 * D2R)], DECBAS) - obs += __create_trace("E", [sin(15 * D2R), sin(30 * D2R)], DECBAS) - obs += __create_trace("Z", [1, 1], DECBAS) + obs += __create_trace("U", [cos(15 * D2R), cos(30 * D2R)], DECBAS) + obs += __create_trace("V", [sin(15 * D2R), sin(30 * D2R)], DECBAS) + obs += __create_trace("W", [1, 1], DECBAS) obs += __create_trace("F", [1, 1], DECBAS) geo = StreamConverter.get_geo_from_obs(obs) X = geo.select(channel="X")[0].data @@ -137,18 +137,18 @@ def test_get_mag_from_geo(): def test_get_mag_from_obs(): """StreamConverter_test.test_get_mag_from_obs() - The observatory stream containing the traces ''h'', ''e'' or ''d'', - ''z'' and ''f'' + The observatory stream containing the traces ''u'', ''v'' or ''d'', + ''w'' and ''f'' """ obs = obspy.core.Stream() - # Call get_mag_from_obs using a DECBAS of 15 degrees, a H stream of - # [cos(15), cos(30)] and a E stream of [sin(15), sin(30)]. + # Call get_mag_from_obs using a DECBAS of 15 degrees, a U stream of + # [cos(15), cos(30)] and a V stream of [sin(15), sin(30)]. # Expect a H stream of [1, 1] and a D stream of [30 degrees, 45 degrees] DECBAS = 15 * D2I - obs += __create_trace("H", [cos(15 * D2R), cos(30 * D2R)], DECBAS) - obs += __create_trace("E", [sin(15 * D2R), sin(30 * D2R)], DECBAS) - obs += __create_trace("Z", [1, 1], DECBAS) + obs += __create_trace("U", [cos(15 * D2R), cos(30 * D2R)], DECBAS) + obs += __create_trace("V", [sin(15 * D2R), sin(30 * D2R)], DECBAS) + obs += __create_trace("W", [1, 1], DECBAS) obs += __create_trace("F", [1, 1], DECBAS) mag = StreamConverter.get_mag_from_obs(obs) H = mag.select(channel="H")[0].data @@ -164,35 +164,35 @@ def test_get_obs_from_geo(): The geographic stream containing the traces ''x'', ''y'', ''z'', and ''f'' converts to the observatory stream containing the traces - ''h'', ''d'' or ''e'', ''z'', and ''f''. + ''u'', ''d'' or ''v'', ''w'', and ''f''. """ geo = obspy.core.Stream() # Call get_geo_from_obs using a decbas of 15, a X stream of # [cos(30), cos(45)], and a Y stream of [sin(30), sin(45)]. - # Expect a H stream of [cos(15), cos(30)] and a - # E stream of [sin(15), sin(30)] + # Expect a U stream of [cos(15), cos(30)] and a + # V stream of [sin(15), sin(30)] DECBAS = 15 * D2I geo += __create_trace("X", [cos(30 * D2R), cos(45 * D2R)], DECBAS) geo += __create_trace("Y", [sin(30 * D2R), sin(45 * D2R)], DECBAS) geo += __create_trace("Z", [1, 1], DECBAS) geo += __create_trace("F", [1, 1], DECBAS) obs = StreamConverter.get_obs_from_geo(geo, True) - H = obs.select(channel="H")[0].data - E = obs.select(channel="E")[0].data + U = obs.select(channel="U")[0].data + V = obs.select(channel="V")[0].data D = obs.select(channel="D")[0].data assert_almost_equal( - H, + U, [cos(15 * D2R), cos(30 * D2R)], 9, - "Expect H to equal [cos(15), cos(30)]", + "Expect U to equal [cos(15), cos(30)]", True, ) assert_almost_equal( - E, + V, [sin(15 * D2R), sin(30 * D2R)], 9, - "Expect E to equal [sin(15), sin(30)", + "Expect V to equal [sin(15), sin(30)", True, ) assert_almost_equal( @@ -205,38 +205,38 @@ def test_get_obs_from_mag(): The magnetic stream containing the traces ''h'', ''d'', ''z'', and ''f'' converts to the observatory stream containing the traces - ''h'', ''e'' and/or ''d'', ''z'', and ''f'' + ''u'', ''v'' and/or ''d'', ''w'', and ''f'' """ mag = obspy.core.Stream() # Call get_obs_from_mag using a decbas of 15, a H stream of [1,1], - # and a D stream of [30 degrees, 45 degrees]. Expect a H stream + # and a D stream of [30 degrees, 45 degrees]. Expect a U stream # of [cos(15), cos(30)], a D stream of [30 degrees, 45 degrees], - # and a E stream of [sin(15), sin(30)] + # and a V stream of [sin(15), sin(30)] DECBAS = 15 * D2I mag += __create_trace("H", [1, 1], DECBAS) mag += __create_trace("D", [30 * D2R, 45 * D2R], DECBAS) mag += __create_trace("Z", [1, 1], DECBAS) mag += __create_trace("F", [1, 1], DECBAS) obs = StreamConverter.get_obs_from_mag(mag, True) - H = obs.select(channel="H")[0].data + U = obs.select(channel="U")[0].data D = obs.select(channel="D")[0].data - E = obs.select(channel="E")[0].data + V = obs.select(channel="V")[0].data assert_almost_equal( - H, + U, [cos(15 * D2R), cos(30 * D2R)], 9, - "Expect H to equal [cos(15), cos(30)", + "Expect U to equal [cos(15), cos(30)", True, ) assert_almost_equal( D, [15 * D2R, 30 * D2R], 9, "Expect D to equal [15 degrees, 30 degrees", True ) assert_almost_equal( - E, + V, [sin(15 * D2R), sin(30 * D2R)], 9, - "Expect E to equal [sin(15), sin(30)", + "Expect V to equal [sin(15), sin(30)", True, ) @@ -244,19 +244,19 @@ def test_get_obs_from_mag(): def test_get_obs_from_obs(): """StreamConverter_test.test_get_obs_from_obs() - The observatory stream can contain either ''d'' or ''e'' depending + The observatory stream can contain either ''d'' or ''v'' depending on it's source. get_obs_from_obs will return either or both as part of the obs Stream. """ - # 1) Call get_obs_from_obs using a decbas of 15, a H stream of - # [cos(15), cos(30)], and a E stream of [sin(15), sin(30)]. + # 1) Call get_obs_from_obs using a decbas of 15, a U stream of + # [cos(15), cos(30)], and a V stream of [sin(15), sin(30)]. # Expect a D stream of [15 degrees, 30 degrees] obs_e = obspy.core.Stream() DECBAS = 15 * D2I - obs_e += __create_trace("H", [cos(15 * D2R), cos(30 * D2R)], DECBAS) - obs_e += __create_trace("E", [sin(15 * D2R), sin(30 * D2R)], DECBAS) - obs_e += __create_trace("Z", [1, 1], DECBAS) + obs_e += __create_trace("U", [cos(15 * D2R), cos(30 * D2R)], DECBAS) + obs_e += __create_trace("V", [sin(15 * D2R), sin(30 * D2R)], DECBAS) + obs_e += __create_trace("W", [1, 1], DECBAS) obs_e += __create_trace("F", [1, 1], DECBAS) obs_D = StreamConverter.get_obs_from_obs(obs_e, False, True) d = obs_D.select(channel="D")[0].data @@ -264,21 +264,21 @@ def test_get_obs_from_obs(): d, [15 * D2R, 30 * D2R], 9, "Expect D to equal [15 degrees, 30 degrees]", True ) - # 2) Call get_obs_from_obs using a decbase of 15 degrees, a H stream of + # 2) Call get_obs_from_obs using a decbase of 15 degrees, a U stream of # [cos(15), cos(30)], and a D stream of [15, 30]. # Expect a D stream of [sin(15), sin(30)] obs_d = obspy.core.Stream() - obs_d += __create_trace("H", [cos(15 * D2R), cos(30 * D2R)], DECBAS) + obs_d += __create_trace("U", [cos(15 * D2R), cos(30 * D2R)], DECBAS) obs_d += __create_trace("D", [15 * D2R, 30 * D2R], DECBAS) - obs_d += __create_trace("Z", [1, 1], DECBAS) + obs_d += __create_trace("W", [1, 1], DECBAS) obs_d += __create_trace("F", [1, 1], DECBAS) - obs_E = StreamConverter.get_obs_from_obs(obs_d, True, False) - e = obs_E.select(channel="E")[0].data + obs_V = StreamConverter.get_obs_from_obs(obs_d, True, False) + v = obs_V.select(channel="V")[0].data assert_almost_equal( - e, + v, [sin(15 * D2R), sin(30 * D2R)], 9, - "Expect E to equal [sin(15), sin(30)", + "Expect V to equal [sin(15), sin(30)", True, ) @@ -298,13 +298,13 @@ def test_verification_data(): DECBAS = 552.7 obs_v = obspy.core.Stream() obs_v += __create_trace( - "H", [20889.55, 20889.57, 20889.74, 20889.86, 20889.91, 20889.81], DECBAS + "U", [20889.55, 20889.57, 20889.74, 20889.86, 20889.91, 20889.81], DECBAS ) obs_v += __create_trace( - "E", [-21.10, -20.89, -20.72, -20.57, -20.39, -20.12], DECBAS + "V", [-21.10, -20.89, -20.72, -20.57, -20.39, -20.12], DECBAS ) obs_v += __create_trace( - "Z", [47565.29, 47565.34, 47565.39, 47565.45, 47565.51, 47565.54], DECBAS + "W", [47565.29, 47565.34, 47565.39, 47565.45, 47565.51, 47565.54], DECBAS ) obs_v += __create_trace( "F", [52485.77, 52485.84, 52485.94, 52486.06, 52486.11, 52486.10], DECBAS diff --git a/test/algorithm_test/AdjustedAlgorithm_test.py b/test/algorithm_test/AdjustedAlgorithm_test.py index 220d498c6f1bf6a65e59243523cd73789b6dc95e..f06b4405181222ec7730a5ed02d8ec5fd1f226ef 100644 --- a/test/algorithm_test/AdjustedAlgorithm_test.py +++ b/test/algorithm_test/AdjustedAlgorithm_test.py @@ -87,8 +87,8 @@ def test_process_reverse_polarity_AdjustedMatrix(): ], pier_correction=-22, ), - inchannels=["H", "E"], - outchannels=["H", "E"], + inchannels=["U", "V"], + outchannels=["U", "V"], ) # load boulder May 20 files from /etc/ directory @@ -101,7 +101,7 @@ def test_process_reverse_polarity_AdjustedMatrix(): adjusted = a.process(raw) assert_streams_almost_equal( - adjusted=adjusted, expected=expected, channels=["H", "E"] + adjusted=adjusted, expected=expected, channels=["U", "V"] ) @@ -141,8 +141,8 @@ def test_process_reverse_polarity_statefile(): # load adjusted data transform matrix and pier correction a = AdjustedAlgorithm( statefile="etc/adjusted/adjbou_state_HE_.json", - inchannels=["H", "E"], - outchannels=["H", "E"], + inchannels=["U", "V"], + outchannels=["U", "V"], ) # load boulder May 20 files from /etc/ directory @@ -155,7 +155,7 @@ def test_process_reverse_polarity_statefile(): adjusted = a.process(raw) assert_streams_almost_equal( - adjusted=adjusted, expected=expected, channels=["H", "E"] + adjusted=adjusted, expected=expected, channels=["U", "V"] ) diff --git a/test/algorithm_test/XYZAlgorithm_test.py b/test/algorithm_test/XYZAlgorithm_test.py index 67be143a880a3ed11b5de59c0d711e0773c205d7..bc1edb16a3160b12512fca5f302e375a6276055b 100644 --- a/test/algorithm_test/XYZAlgorithm_test.py +++ b/test/algorithm_test/XYZAlgorithm_test.py @@ -13,9 +13,9 @@ def test_xyzalgorithm_process(): """ algorithm = XYZAlgorithm("obs", "geo") timeseries = Stream() - timeseries += __create_trace("H", [1, 1]) - timeseries += __create_trace("E", [1, 1]) - timeseries += __create_trace("Z", [1, 1]) + timeseries += __create_trace("U", [1, 1]) + timeseries += __create_trace("V", [1, 1]) + timeseries += __create_trace("W", [1, 1]) timeseries += __create_trace("F", [1, 1]) outputstream = algorithm.process(timeseries) assert_equal(outputstream[0].stats.channel, "X") @@ -28,7 +28,7 @@ def test_xyzalgorithm_channels(): informat/outformat during instantiation. """ algorithm = XYZAlgorithm("obs", "geo") - inchannels = ["H", "E", "Z", "F"] + inchannels = ["U", "V", "W", "F"] outchannels = ["X", "Y", "Z", "F"] assert_equal(algorithm.get_input_channels(), inchannels) assert_equal(algorithm.get_output_channels(), outchannels) @@ -38,13 +38,13 @@ def test_xyzalgorithm_limited_channels(): """XYZAlgorithm_test.test_xyzalgorithm_limited_channels() confirms that only the required channels are necessary for processing - ie. 'H' and 'E' are only needed to get 'X' and 'Y' without 'Z' or 'F' + ie. 'U' and 'V' are only needed to get 'X' and 'Y' without 'Z' or 'F' """ algorithm = XYZAlgorithm("obs", "mag") count = 5 timeseries = Stream() - timeseries += __create_trace("H", [2] * count) - timeseries += __create_trace("E", [3] * count) + timeseries += __create_trace("U", [2] * count) + timeseries += __create_trace("V", [3] * count) outstream = algorithm.process(timeseries) ds = outstream.select(channel="D") # there is 1 trace @@ -66,14 +66,14 @@ def test_xyzalgorithm_uneccesary_channel_empty(): """ algorithm = XYZAlgorithm("obs", "mag") timeseries = Stream() - timeseries += __create_trace("H", [1, 1]) - timeseries += __create_trace("E", [1, 1]) - timeseries += __create_trace("Z", [1, np.NaN]) + timeseries += __create_trace("U", [1, 1]) + timeseries += __create_trace("V", [1, 1]) + timeseries += __create_trace("W", [1, np.NaN]) timeseries += __create_trace("F", [np.NaN, np.NaN]) outstream = algorithm.process(timeseries) assert_equal( - outstream.select(channel="Z")[0].data.all(), - timeseries.select(channel="Z")[0].data.all(), + outstream.select(channel="W")[0].data.all(), + timeseries.select(channel="W")[0].data.all(), ) assert_equal( outstream.select(channel="F")[0].data.all(), diff --git a/test/edge_test/EdgeFactory_test.py b/test/edge_test/EdgeFactory_test.py index fca38a8c8df6fb8cd08a7717ff2114f5e7f5daf3..599299d1fd3423d66cdc9a9cd66b98aff6e774f1 100644 --- a/test/edge_test/EdgeFactory_test.py +++ b/test/edge_test/EdgeFactory_test.py @@ -25,6 +25,9 @@ def test__get_edge_channel(): 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("", "U", "", "minute"), "MVH") + assert_equal(EdgeFactory()._get_edge_channel("", "V", "", "minute"), "MVE") + assert_equal(EdgeFactory()._get_edge_channel("", "W", "", "minute"), "MVZ") 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") diff --git a/test/edge_test/MiniSeedFactory_test.py b/test/edge_test/MiniSeedFactory_test.py index a0c57869e7ff0ffcea37f7c6f5c98842347e2492..3a7fde61837a09d73485077f4db92b265f5c9303 100644 --- a/test/edge_test/MiniSeedFactory_test.py +++ b/test/edge_test/MiniSeedFactory_test.py @@ -98,7 +98,7 @@ def test__pre_process(): processed = MiniSeedInputClient(host=None)._pre_process(stream=Stream(trace)) assert len(processed) == 2 for trace in processed: - assert trace.data.dtype == "float32" + assert trace.data.dtype == "float64" stats = trace.stats assert stats.npts == 86400 assert stats.starttime.timestamp % 86400 == 0 @@ -110,7 +110,7 @@ def test__format_miniseed(): buf = io.BytesIO() trace = __create_trace(numpy.arange((86400 * 2) + 1), channel="H") MiniSeedInputClient(host=None)._format_miniseed(stream=Stream(trace), buf=buf) - block_size = 512 + block_size = 1024 data = buf.getvalue() n_blocks = int(len(data) / block_size) assert n_blocks == 1516