From 1885e2fb223d7f262aca24283ef389ac2934d406 Mon Sep 17 00:00:00 2001
From: Alex Wernle <awernle@usgs.gov>
Date: Fri, 4 Oct 2024 10:10:07 -0600
Subject: [PATCH] Deleted field-work attribute and added Field_Work to
 categories. Deleted source and added additional validators and class methods
 to ArtificialDisturbances.

---
 geomagio/metadata/flag/Flag.py | 78 +++++++++++++++++++++-------------
 1 file changed, 48 insertions(+), 30 deletions(-)

diff --git a/geomagio/metadata/flag/Flag.py b/geomagio/metadata/flag/Flag.py
index a16c6363..b9d4c98e 100644
--- a/geomagio/metadata/flag/Flag.py
+++ b/geomagio/metadata/flag/Flag.py
@@ -1,7 +1,6 @@
 from typing import Dict, Union, List, Optional
 from datetime import timedelta
 
-import numpy as np
 from obspy import UTCDateTime
 from pydantic import BaseModel, Field, validator
 from enum import Enum
@@ -11,6 +10,7 @@ class FlagCategory(str, Enum):
     ARTIFICIAL_DISTURBANCE = "ARTIFICIAL_DISTURBANCE"
     GAP = "GAP"
     EVENT = "EVENT"
+    FIELD_WORK = "FIELD_WORK"
     OTHER = "OTHER"
 
 
@@ -23,30 +23,26 @@ class Flag(BaseModel):
         automatic_flag = Metadata(
             created_by='ex_algorithm',
             start_time=UTCDateTime('2023-01-01T03:05:10'),
-            end_time=UTCDateTime('2023-01-01T03:05:11'),
+            end_time=UTCDateTime('2023-01-01T03:10:11'),
             network='NT',
             station='BOU',
             channel='BEH',
             category=MetadataCategory.FLAG,
             comment="spike detected",
             priority=1,
-            data_valid=False,
+            data_valid=True,
             metadata= ArtificialDisturbance{
-                "description": "Spike in magnetic field strength",
-                "field_work": false,
-                "corrected": false,
+                "description": "Spikes in magnetic field strength",
                 "flag_category": ARTIFICIAL_DISTURBANCE,
                 "artificial_disturbance_type": ArtificialDisturbanceType.SPIKE,
-                "source": "Lightning",
                 "deviation": None,
+                "spikes": ['2023-01-01T03:05:10','2023-01-01T03:07:20','2023-01-01T03:10:11']
         }
     )
         ```
     """
 
     description: str = Field(..., description="Description of the flag")
-    field_work: bool = Field(..., description="Flag signaling field work")
-    corrected: int = Field(..., description="Corrected ID for processing stage")
     flag_category: FlagCategory = "OTHER"
 
 
@@ -70,24 +66,56 @@ class ArtificialDisturbance(Flag):
     ----------
     artificial_disturbance_type:ArtificialDisturbanceType
         The type of artificial disturbance(s).
-    source: str
-        Source of the disturbance if known or suspected.
     deviation: float
        Deviation of an offset in nt.
-    spikes: np.ndarray
-        NumPy array of timestamps as UTCDateTime. Can be a single spike or many spikes.
+    spikes: List[UTCDateTime]
+        Array of timestamps as UTCDateTime. Can be a single spike or many spikes.
 
     """
 
     artificial_disturbance_type: ArtificialDisturbanceType
     deviation: Optional[float] = None
-    source: Optional[str] = None
-    spikes: Optional[np.ndarray] = None
+    spikes: Optional[List[UTCDateTime]] = None
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.flag_category = "ARTIFICIAL_DISTURBANCE"
 
+    @validator("spikes", always=True)
+    def validate_spikes(cls, spikes):
+        if len(spikes) == 0:
+            raise ValueError("Spikes list cannot be empty.")
+
+        return spikes
+
+    @validator("spikes", always=True)
+    def check_spikes_duration(cls, spikes):
+        if spikes is None or len(spikes) < 2:
+            return spikes
+
+        duration = spikes[-1] - spikes[0]
+        if duration > timedelta(days=1).total_seconds():
+            raise ValueError(
+                f"The duration between the first and last spike timestamp must not exceed 1 day. Duration: {duration} seconds"
+            )
+
+        return spikes
+
+    @classmethod
+    def check_spikes_match_times(cls, spikes, values):
+        metadata_starttime = values.get("starttime")
+        metadata_endtime = values.get("endtime")
+
+        if spikes[0] != metadata_starttime:
+            raise ValueError(
+                f"The first spike timestamp {spikes[0]} does not match the starttime {metadata_starttime}."
+            )
+
+        if spikes[-1] != metadata_endtime:
+            raise ValueError(
+                f"The last spike timestamp {spikes[-1]} does not match the endtime {metadata_endtime}."
+            )
+
 
 class Gap(Flag):
     """
@@ -145,37 +173,27 @@ class Event(Flag):
 
 
 # More example usage:
-timestamps_array = np.array(
-    [
-        UTCDateTime("2023-11-16T12:00:0"),
-        UTCDateTime("2023-11-16T12:01:10"),
-        UTCDateTime("2023-11-16T12:02:30"),
-    ]
-)
+timestamps_array = [
+    UTCDateTime("2023-11-16T12:00:0"),
+    UTCDateTime("2023-11-16T12:01:10"),
+    UTCDateTime("2023-11-16T12:02:30"),
+]
 
 spikes_data = {
     "starttime": "2023-11-16 12:00:00",
     "endtime": "2023-11-16 12:02:30",
     "description": "Spikes description",
-    "field_work": False,
-    "corrected": 32265,
     "disturbance_type": ArtificialDisturbanceType.SPIKES,
-    "source": "processing",
     "spikes": timestamps_array,
 }
 
 offset_data = {
     "description": "Offset description",
-    "field_work": False,
-    "corrected": 47999,
     "disturbance_type": ArtificialDisturbanceType.OFFSET,
-    "source": "Bin change",
     "deviation": 10.0,
 }
 geomagnetic_storm_data = {
     "description": "Geomagnetic storm",
-    "field_work": False,
-    "corrected": 36999,
     "event_type": EventType.GEOMAGNETIC_STORM,
     "scale": "G3",
     "index": 7,
-- 
GitLab