diff --git a/geomagio/metadata/Flag.py b/geomagio/metadata/Flag.py new file mode 100644 index 0000000000000000000000000000000000000000..0791f94c63958100b7d247417f27244a75e0e7d3 --- /dev/null +++ b/geomagio/metadata/Flag.py @@ -0,0 +1,206 @@ +from typing import Dict, Union, List +from datetime import timedelta + +from obspy import UTCDateTime +from pydantic import BaseModel, Field, validator +from enum import Enum + + +# Are channels defined elsewhere? +class ChannelType(str, Enum): + H = "H" + E = "E" + X = "X" + Y = "Y" + Z = "Z" + D = "D" + F = "F" + + +class Flag(BaseModel): + """ + Base class for flagging features in magnetic timeseries data. + + Flag example: + ``` + automatic_flag = Metadata( + created_by='ex_algorithm', + start_time=UTCDateTime('2023-01-01T00:00:00'), + end_time=UTCDateTime('2023-01-01T23:59:59'), + network='NT', + station='BOU', + channel='BEU', + category=MetadataCategory.FLAG, + comment="spike detected", + priority=1, + data_valid=False, + metadata= Spikes{ + "starttime": "2023-01-01T03:05:00", + "endtime": "2023-01-01T03:07:00", + "channels": "F", + "description": "Spike in magnetic field strength", + "field_work": false, + "magnitude": 16 nt, + } + ) + ``` + """ + + starttime: UTCDateTime = None + endtime: UTCDateTime = None + channels: Union[ChannelType, List[ChannelType]] + description: str = Field(..., description="Description of the flag") + field_work: bool = Field(..., description="Flag signaling field work") + corrective_action: bool = Field( + ..., + description="whether or not corrective action has been taken for spikes, noise, etc.", + ) + + +class Noise(Flag): + """ + This class is used to flag noise. + + Noise can refer to random or unwanted variations in the magnetic field. + Typically it lacks a pattern, has varying amplitudes and frequency distributions. + Noise can be natural or unnatural. + + Attributes + ---------- + noise_level: float + Level of noise in the magnetic time series in decibels. + noise_source: str + Source of the noise. + filtered: bool + Whether the noise has been filtered. + filter_used: str + Type of filter used. This could be linked to another class representing processing tools. + """ + + noise_level: float = Field( + None, description="Level of noise in the magnetic time series in dB" + ) + noise_source: str = Field(None, description="Source of the noise") + filtered: bool + filter_used: str = Field(None, description="Type of filter used") + + +class Spikes(Flag): + """ + This class is used to flag spikes. + + a spike refers to a sudden, short-duration increase or decrease in the magnetic field. + Spikes are short-lived events and should appear as a single sample within the timeseries. + + Attributes + ---------- + magnitude: float + Magnitude of spike in nt. + """ + + magnitude: float # we need to define what this magnitude is relative to + + # add validator based on frequency? + + +class Gaps(Flag): + """ + This class is used to flag gaps in data. + + A gap is a period where data is missing or not recorded. + + Attributes + ---------- + duration: timedelta + Length of time during which data is missing. + cause: str + Cause of gap, e.g., network outage. + handling: str + How the gap is being handled, e.g., backfilled. + """ + + duration: timedelta + cause: str = None + handling: str = None + + +class Offsets(Flag): + """ + This class is used to flag offsets. + + An offset refers to a relatively constant shift or deviation in the baseline magnetic field + strength lasting for a duration or permanantly like a step. + + Attributes + ---------- + magnitude: float + A constant value added to or subtracted from the magnetic field strength (nt). + duration: timedelta + Length of the offset. + """ + + magnitude: float + duration: timedelta + + +class AdjustedAlgorithmOffsets(Flag): + """ + This class is used to flag shifts made by the Adjusted Algorithm. + + Attributes + ---------- + adjustments: Dict + Adjustments made by the algorithm. + """ + + adjustments: Dict + + +class Events(Flag): + """ + This class is used to flag an event of interest such as a geomagnetic storm or earthquake. + + Attributes + ---------- + geomagnetic_storm: bool + Geomagnetic storm period. + """ + + geomagnetic_storm: bool = None # if true, ignore spike detection filter + + +class Anomalies(Flag): + """ + This class is used to flag anything that does not fall under the above categories. + + Attributes + ---------- + """ + + +# More example usage: +noise_data = { + "starttime": "2023-11-16 12:00:00", + "endtime": "2023-11-16 12:15:00", + "channels": "X", + "metadata": {"key1": "value1", "key2": "value2"}, + "description": "Noise description", + "field_work": True, + "noise_level": 0.2, +} + +spikes_data = { + "starttime": "2023-11-16 12:00:00", + "endtime": "2023-11-16 12:15:00", + "channels": ["X", "Y", "Z"], + "metadata": {"key1": "value1", "key2": "value2"}, + "description": "Spikes description", + "field_work": True, + "magnitude": 5.0, +} + +single_channel_instance = Noise(**noise_data) +multiple_channels_instance = Spikes(**spikes_data) + +print(single_channel_instance.dict()) +print(multiple_channels_instance.dict())