1# =====================================================
2# Imports
3# =====================================================
4from typing import Annotated
5
6from pydantic import Field
7
8from mt_metadata.base import MetadataBase
9from mt_metadata.common.enumerations import ChannelEnum
10
11
12# =====================================================
13
14
15class Channel(MetadataBase):
16 number: Annotated[
17 int | None,
18 Field(
19 default=None,
20 description="Channel number",
21 alias=None,
22 json_schema_extra={
23 "units": None,
24 "required": True,
25 "examples": ["1"],
26 },
27 ),
28 ]
29
30 azimuth: Annotated[
31 float,
32 Field(
33 default=0.0,
34 description="channel azimuth",
35 alias=None,
36 json_schema_extra={
37 "units": "degrees",
38 "required": True,
39 "examples": ["90"],
40 },
41 ),
42 ]
43
44 tilt: Annotated[
45 float,
46 Field(
47 default=0.0,
48 description="channel tilt relative to horizontal.",
49 alias=None,
50 json_schema_extra={
51 "units": "degrees",
52 "required": True,
53 "examples": ["100.0"],
54 },
55 ),
56 ]
57
58 dl: Annotated[
59 float | str,
60 Field(
61 default=0.0,
62 description="dipole length in meters",
63 alias=None,
64 json_schema_extra={
65 "units": "meters",
66 "required": True,
67 "examples": ["0.0"],
68 },
69 ),
70 ]
71
72 channel: Annotated[
73 ChannelEnum,
74 Field(
75 default="",
76 description="channel name",
77 alias=None,
78 json_schema_extra={
79 "units": None,
80 "required": True,
81 "examples": ["hx"],
82 },
83 ),
84 ]
85
86 @property
87 def channel_string(self) -> str:
88 """Return the channel name as a string for indexing purposes."""
89 if hasattr(self.channel, "value"):
90 return self.channel.value
91 return str(self.channel)
92
93 def __str__(self):
94 lines = ["Channel Metadata:"]
95 for key in ["channel", "number", "dl", "azimuth", "tilt"]:
96 try:
97 value = getattr(self, key)
98 # Special formatting for different field types
99 if key == "channel" and hasattr(value, "value"):
100 # For enums, use the string value
101 if value.value == "":
102 display_value = "None"
103 else:
104 display_value = value.value
105 elif key == "number" and value is None:
106 # Skip None number field completely
107 continue
108 else:
109 display_value = value
110 lines.append(f"\t{key.capitalize()}: {display_value:<12}")
111 except TypeError:
112 pass
113 return "\n".join(lines)
114
115 def __repr__(self):
116 return self.__str__()
117
118 @property
119 def index(self):
120 if self.number is not None:
121 return self.number - 1
122 else:
123 return None
124
125 def from_dict(self, channel_dict):
126 """
127 fill attributes from a dictionary
128 """
129
130 for key, value in channel_dict.items():
131 if key in ["azm", "azimuth", "measurement_azimuth"]:
132 self.azimuth = value
133 elif key in ["chn_num", "number"]:
134 self.number = value
135 elif key in ["tilt", "measurement_tilt"]:
136 self.tilt = value
137 elif key in ["dl", "dipole_length"]:
138 self.dl = value
139 elif key in ["channel", "component"]:
140 self.channel = value