From a4bc6d95fba3ac6cbd607af810d850ed3c614cab Mon Sep 17 00:00:00 2001
From: "E. Joshua Rigler" <erigler@usgs.gov>
Date: Mon, 20 Mar 2023 16:31:37 -0600
Subject: [PATCH 1/3] print nothing if sensor_sampling_rate is not invertable

The _format_headers() function in IAGA2002Writer.py would choke when
the sensor_sampling_rate parameter in the trace.stats metadata could
not be inverted. This occurred, at least, when the "Digital Sampling"
IAGA2002 header line was not parsed properly, or was blank.
---
 geomagio/iaga2002/IAGA2002Writer.py | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/geomagio/iaga2002/IAGA2002Writer.py b/geomagio/iaga2002/IAGA2002Writer.py
index bd215ef98..4aac8db92 100644
--- a/geomagio/iaga2002/IAGA2002Writer.py
+++ b/geomagio/iaga2002/IAGA2002Writer.py
@@ -87,11 +87,15 @@ class IAGA2002Writer(object):
                 self._format_header("Sensor Orientation", stats.sensor_orientation)
             )
         if "sensor_sampling_rate" in stats:
-            buf.append(
-                self._format_header(
-                    "Digital Sampling", str(1 / stats.sensor_sampling_rate) + " second"
+            try:
+                buf.append(
+                    self._format_header(
+                        "Digital Sampling",
+                        str(1 / stats.sensor_sampling_rate) + " second",
+                    )
                 )
-            )
+            except TypeError:
+                buf.append(self._format_header("Digital Sampling", ""))
         if "data_interval_type" in stats:
             buf.append(
                 self._format_header("Data Interval Type", stats.data_interval_type)
-- 
GitLab


From af72dc0ff323eed8a1ce5ca87b0c76f223cd7050 Mon Sep 17 00:00:00 2001
From: "E. Joshua Rigler" <erigler@usgs.gov>
Date: Mon, 20 Mar 2023 16:39:31 -0600
Subject: [PATCH 2/3] Force traces in stream to first dtype before merge

A Stream corresponding to a given network, station, location, and
channel can (but probably shouldn't) have more than 1 trace returned
from an ObsPy client.get_waveforms() function. This happens, for
example, when the data type generated by a given station changes.
This change forces the dtype of the data array for all Traces in
the Stream to match the dtype of the data array in the first Trace
of the Stream, thus allowing the Stream.merge() function to work
as intended.
---
 geomagio/edge/MiniSeedFactory.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/geomagio/edge/MiniSeedFactory.py b/geomagio/edge/MiniSeedFactory.py
index ff03c0406..c9c3122c1 100644
--- a/geomagio/edge/MiniSeedFactory.py
+++ b/geomagio/edge/MiniSeedFactory.py
@@ -361,6 +361,8 @@ class MiniSeedFactory(TimeseriesFactory):
         data = self.client.get_waveforms(
             sncl.network, sncl.station, sncl.location, sncl.channel, starttime, endtime
         )
+        for trace in data:
+            trace.data = trace.data.astype(data[0].data.dtype)
         data.merge()
         if data.count() == 0 and add_empty_channels:
             data += self._get_empty_trace(
-- 
GitLab


From c2c6c6444b3d8aceaffe095a108246523ffde4a7 Mon Sep 17 00:00:00 2001
From: "E. Joshua Rigler" <erigler@usgs.gov>
Date: Tue, 21 Mar 2023 14:42:03 -0600
Subject: [PATCH 3/3] Fixes issue #77

As per discussion in issue #77 with Dave K., this commit adds delta/2
to the requested `endtime` to ensure that starttime and endtime are
fully inclusive in Edge-related I/O factories. I would have liked to
generalized this and reduce the duplicate code between EdgeFactory
and MiniSeedFactory, but couldn't figure out how to do this without
adding considerably *more* code to the project than what is in this
commit.
---
 geomagio/edge/EdgeFactory.py     |  6 +++++-
 geomagio/edge/MiniSeedFactory.py | 11 ++++++++++-
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/geomagio/edge/EdgeFactory.py b/geomagio/edge/EdgeFactory.py
index 525999834..d07f3fa5e 100644
--- a/geomagio/edge/EdgeFactory.py
+++ b/geomagio/edge/EdgeFactory.py
@@ -333,6 +333,10 @@ class EdgeFactory(TimeseriesFactory):
             element=channel,
             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
         try:
             data = self.client.get_waveforms(
                 sncl.network,
@@ -340,7 +344,7 @@ class EdgeFactory(TimeseriesFactory):
                 sncl.location,
                 sncl.channel,
                 starttime,
-                endtime,
+                endtime + half_delta,
             )
         except TypeError:
             # get_waveforms() fails if no data is returned from Edge
diff --git a/geomagio/edge/MiniSeedFactory.py b/geomagio/edge/MiniSeedFactory.py
index c9c3122c1..daf02420c 100644
--- a/geomagio/edge/MiniSeedFactory.py
+++ b/geomagio/edge/MiniSeedFactory.py
@@ -358,8 +358,17 @@ class MiniSeedFactory(TimeseriesFactory):
             element=channel,
             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
         data = self.client.get_waveforms(
-            sncl.network, sncl.station, sncl.location, sncl.channel, starttime, endtime
+            sncl.network,
+            sncl.station,
+            sncl.location,
+            sncl.channel,
+            starttime,
+            endtime + half_delta,
         )
         for trace in data:
             trace.data = trace.data.astype(data[0].data.dtype)
-- 
GitLab