Coverage for C: \ Users \ peaco \ OneDrive \ Documents \ GitHub \ mt_metadata \ mt_metadata \ timeseries \ stationxml \ xml_equipment_mt_run.py: 88%
68 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-10 00:11 -0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-10 00:11 -0800
1# -*- coding: utf-8 -*-
2"""
3Created on Thu Feb 18 12:49:13 2021
5:copyright:
6 Jared Peacock (jpeacock@usgs.gov)
8:license: MIT
10"""
11# =============================================================================
12# Imports
13# =============================================================================
14import enum
16from mt_metadata import timeseries as metadata
17from mt_metadata.base.helpers import requires
18from mt_metadata.timeseries.stationxml.utils import BaseTranslator
21try:
22 from obspy.core import inventory
23except ImportError:
24 inventory = None
26# =============================================================================
29@requires(obspy=inventory)
30class XMLEquipmentMTRun(BaseTranslator):
31 """
32 translate back and forth between StationXML Station and MT Station
33 """
35 def __init__(self):
36 super().__init__()
38 self.xml_translator = {
39 "type": "data_type",
40 "manufacturer": "data_logger.manufacturer",
41 "model": "data_logger.model",
42 "serial_number": "data_logger.id",
43 "installation_date": "time_period.start",
44 "removal_date": "time_period.end",
45 "description": "special",
46 "resource_id": "id",
47 }
49 # StationXML to MT Survey
50 self.mt_translator = self.flip_dict(self.xml_translator)
51 self.mt_translator["notes"] = "description"
53 self.mt_comments_list = [
54 {"acquired_by": ["acquired_by.author", "acquired_by.comments"]},
55 {"metadata_by": ["metadata_by.author", "metadata_by.comments"]},
56 "comments",
57 ]
59 self.mt_description_list = [
60 "data_logger.firmware.author",
61 "data_logger.firmware.name",
62 "data_logger.firmware.version",
63 "data_logger.power_source.comments.value",
64 "data_logger.power_source.id",
65 "data_logger.power_source.type",
66 "data_logger.power_source.voltage.end",
67 "data_logger.power_source.voltage.start",
68 "data_logger.timing_system.comments.value",
69 "data_logger.timing_system.drift",
70 "data_logger.timing_system.type",
71 "data_logger.timing_system.uncertainty",
72 "data_logger.type",
73 ]
75 def xml_to_mt(self, equipment):
76 """
77 Read in an equipment block.
79 :param equipment: an Equipment element
80 :type equipment: :class:`obspy.core.inventory.Equipment`
82 """
84 if not isinstance(equipment, inventory.Equipment):
85 msg = f"Input must be obspy.core.inventory.Equipment object not {type(equipment)}"
86 self.logger.error(msg)
87 raise TypeError(msg)
89 mt_run = metadata.Run()
90 for xml_key, mt_key in self.xml_translator.items():
91 value = getattr(equipment, xml_key)
92 if xml_key in ["description"]:
93 mt_run = self._parse_description(value, mt_run)
94 elif xml_key in ["resource_id"]:
95 mt_run.id = value.split(":")[1]
96 elif xml_key in ["installation_date", "removal_date"]:
97 # Handle time fields - convert from ObsPy UTCDateTime to string
98 if value is not None:
99 # Convert ObsPy UTCDateTime to ISO format string for MTime objects
100 value = str(value)
101 mt_run.update_attribute(mt_key, value)
102 else:
103 mt_run.update_attribute(mt_key, value)
105 return mt_run
107 def mt_to_xml(self, mt_run):
108 """
109 Convert an :class:mt_metadata.timeseries.Run` to XML equipment and comments
111 :param mt_run: DESCRIPTION
112 :type mt_run: TYPE
113 :return: DESCRIPTION
114 :rtype: TYPE
116 """
118 equipment = inventory.Equipment()
119 for mt_key, xml_key in self.mt_translator.items():
120 if mt_key == "notes":
121 value = self._make_description(mt_run)
122 elif mt_key == "id":
123 value = f"mt.run.id:{mt_run.id}"
124 elif "date" in xml_key:
125 time_obj = mt_run.get_attr_from_name(mt_key)
126 # Convert MTime object to ISO format string for ObsPy UTCDateTime
127 value = (
128 time_obj.isoformat()
129 if hasattr(time_obj, "isoformat")
130 else time_obj.time_stamp
131 )
132 else:
133 value = mt_run.get_attr_from_name(mt_key)
134 # Handle enum values by getting their actual value instead of string representation
135 if isinstance(value, enum.Enum):
136 value = value.value
137 setattr(equipment, xml_key, value)
139 return equipment
141 def _parse_description(self, description, run_obj):
142 """
143 Parse a run description into run
145 :param description: DESCRIPTION
146 :type description: TYPE
147 :return: DESCRIPTION
148 :rtype: TYPE
150 """
152 for d_str in description.split(","):
153 d_key, d_value = d_str.split(":")
154 d_value = d_value.strip()
155 if not d_value in ["", "None", "null"]:
156 run_obj.update_attribute(
157 f"data_logger.{d_key.strip()}", d_value.strip()
158 )
160 return run_obj
162 def _make_description(self, run_obj):
163 """
164 Make an Equipment description from a run object
166 :param run_obj: DESCRIPTION
167 :type run_obj: TYPE
168 :return: DESCRIPTION
169 :rtype: TYPE
171 """
172 if not isinstance(run_obj, metadata.Run):
173 msg = (
174 f"Input must be a mt_metadta.timeseries.Run object not {type(run_obj)}"
175 )
176 self.logger.error(msg)
177 raise TypeError(msg)
179 lines = []
180 for key in self.mt_description_list:
181 value = run_obj.get_attr_from_name(key)
182 if value:
183 lines.append(f"{key.split('data_logger.')[1]}: {value}")
185 return ", ".join(lines)