14
14
15
15
from mt_metadata .transfer_functions .core import TF
16
16
17
- from mtpy .core import Z , Tipper
17
+ from mtpy .core import Z , Tipper , COORDINATE_REFERENCE_FRAME_OPTIONS
18
18
from mtpy .core .mt_location import MTLocation
19
19
from mtpy .core .mt_dataframe import MTDataFrame
20
20
from mtpy .utils .estimate_tf_quality_factor import EMTFStats
@@ -38,8 +38,40 @@ class MT(TF, MTLocation):
38
38
letter represents the output channels and the second letter represents
39
39
the input channels.
40
40
41
- For exampe for an input of Hx and an output of Ey the impedance tensor
41
+ For example for an input of Hx and an output of Ey the impedance tensor
42
42
element is Zyx.
43
+
44
+ Coordinate reference frame of the transfer function is by defualt is NED
45
+
46
+ - x = North
47
+ - y = East
48
+ - z = + Down
49
+
50
+ The other option is ENU
51
+
52
+ - x = East
53
+ - y = North
54
+ - z = + Up
55
+
56
+ Other input options for the NED are:
57
+
58
+ - "+"
59
+ - "z+"
60
+ - "nez+"
61
+ - "ned"
62
+ - "exp(+ i\\ omega t)"
63
+ - "exp(+i\\ omega t)"
64
+ - None
65
+
66
+ And for ENU:
67
+
68
+ - "-"
69
+ - "z-"
70
+ - "enz-"
71
+ - "enu"
72
+ - "exp(- i\\ omega t)"
73
+ - "exp(-i\\ omega t)"
74
+
43
75
"""
44
76
45
77
def __init__ (self , fn = None , ** kwargs ):
@@ -65,9 +97,6 @@ def __init__(self, fn=None, **kwargs):
65
97
TF .__init__ (self , ** tf_kwargs )
66
98
MTLocation .__init__ (self , survey_metadata = self ._survey_metadata )
67
99
68
- # MTLocation.__init__(self)
69
- # TF.__init__(self)
70
-
71
100
self .fn = fn
72
101
73
102
self ._Z = Z ()
@@ -76,6 +105,14 @@ def __init__(self, fn=None, **kwargs):
76
105
77
106
self .save_dir = Path .cwd ()
78
107
108
+ self ._coordinate_reference_frame_options = (
109
+ COORDINATE_REFERENCE_FRAME_OPTIONS
110
+ )
111
+
112
+ self .coordinate_reference_frame = (
113
+ self .station_metadata .transfer_function .sign_convention
114
+ )
115
+
79
116
for key , value in kwargs .items ():
80
117
setattr (self , key , value )
81
118
@@ -115,9 +152,68 @@ def copy(self):
115
152
"""Copy function."""
116
153
return deepcopy (self )
117
154
155
+ @property
156
+ def coordinate_reference_frame (self ):
157
+ f"""Coordinate reference frame of the transfer function
158
+
159
+ Deafualt is NED
160
+
161
+ - x = North
162
+ - y = East
163
+ - z = + down
164
+
165
+ Options are:
166
+
167
+ { self ._coordinate_reference_frame_options }
168
+
169
+ """
170
+
171
+ return self ._coordinate_reference_frame_options [
172
+ self .station_metadata .transfer_function .sign_convention
173
+ ].upper ()
174
+
175
+ @coordinate_reference_frame .setter
176
+ def coordinate_reference_frame (self , value ):
177
+ """set coordinate_reference_frame
178
+
179
+ options are NED, ENU
180
+
181
+ NED
182
+
183
+ - x = North
184
+ - y = East
185
+ - z = + down
186
+
187
+ ENU
188
+
189
+ - x = East
190
+ - y = North
191
+ - z = + up
192
+ """
193
+
194
+ if value is None :
195
+ value = "+"
196
+ if value .lower () not in self ._coordinate_reference_frame_options :
197
+ raise ValueError (
198
+ f"{ value } is not understood as a reference frame. "
199
+ f"Options are { self ._coordinate_reference_frame_options } "
200
+ )
201
+ if value in ["ned" ] or "+" in value :
202
+ value = "+"
203
+ elif value in ["enu" ] or "-" in value :
204
+ value = "-"
205
+ self .logger .warning (
206
+ "MTpy-v2 is assumes a NED coordinate system where x=North, "
207
+ "y=East, z=+down. By changing to ENU there maybe some "
208
+ "incorrect values for angles and derivative products of the "
209
+ "impedance tensor."
210
+ )
211
+
212
+ self .station_metadata .transfer_function .sign_convention = value
213
+
118
214
@property
119
215
def rotation_angle (self ):
120
- """Rotation angle in degrees from north."""
216
+ """Rotation angle in degrees from north. In the coordinate reference frame """
121
217
return self ._rotation_angle
122
218
123
219
@rotation_angle .setter
@@ -127,7 +223,7 @@ def rotation_angle(self, theta_r):
127
223
128
224
upon setting rotates Z and Tipper
129
225
130
- TODO figure this out with xarray
226
+ TODO: figure this out with xarray
131
227
"""
132
228
133
229
self .rotate (theta_r )
@@ -136,32 +232,49 @@ def rotation_angle(self, theta_r):
136
232
def rotate (self , theta_r , inplace = True ):
137
233
"""Rotate the data in degrees assuming North is 0 measuring clockwise
138
234
positive to East as 90.
139
- :param theta_r: DESCRIPTION.
140
- :type theta_r: TYPE
141
- :param inplace: DESCRIPTION, defaults to True.
142
- :type inplace: TYPE, optional
143
- :return: DESCRIPTION.
144
- :rtype: TYPE
235
+
236
+ :param theta_r: rotation angle to rotate by in degrees.
237
+ :type theta_r: float
238
+ :param inplace: rotate all transfer function in place, defaults to True.
239
+ :type inplace: bool, optional
240
+ :return: if inplace is False, returns a new MT object.
241
+ :rtype: MT object
242
+
145
243
"""
146
244
245
+ if self .has_impedance ():
246
+ new_z = self .Z .rotate (
247
+ theta_r ,
248
+ inplace = False ,
249
+ coordinate_reference_frame = self .coordinate_reference_frame ,
250
+ )
251
+ if self .has_tipper ():
252
+ new_t = self .Tipper .rotate (
253
+ theta_r ,
254
+ inplace = False ,
255
+ coordinate_reference_frame = self .coordinate_reference_frame ,
256
+ )
257
+
147
258
if inplace :
148
259
if self .has_impedance ():
149
- self .Z = self . Z . rotate ( theta_r )
260
+ self .Z = new_z
150
261
if self .has_tipper ():
151
- self .Tipper = self . Tipper . rotate ( theta_r )
262
+ self .Tipper = new_t
152
263
153
- self ._rotation_angle = theta_r
264
+ self ._rotation_angle + = theta_r
154
265
155
266
self .logger .info (
156
- f"Rotated transfer function by: { self ._rotation_angle :.3f} degrees clockwise"
267
+ f"Rotated transfer function by: { self ._rotation_angle :.3f} "
268
+ "degrees clockwise in reference frame "
269
+ f"{ self .coordinate_reference_frame } ."
157
270
)
158
271
else :
159
272
new_m = self .clone_empty ()
160
273
if self .has_impedance ():
161
- new_m .Z = self . Z . rotate ( theta_r )
274
+ new_m .Z = new_z
162
275
if self .has_tipper ():
163
- new_m .Tipper = self . Tipper . rotate ( theta_r )
164
- new_m ._rotation_angle = self . _rotation_angle
276
+ new_m .Tipper = new_t
277
+ new_m ._rotation_angle += theta_r
165
278
return new_m
166
279
167
280
@property
@@ -959,7 +1072,9 @@ def add_white_noise(self, value, inplace=True):
959
1072
] = self ._transfer_function .transfer_function .real * (
960
1073
noise_real
961
1074
) + (
962
- 1j * self ._transfer_function .transfer_function .imag * noise_imag
1075
+ 1j
1076
+ * self ._transfer_function .transfer_function .imag
1077
+ * noise_imag
963
1078
)
964
1079
965
1080
self ._transfer_function ["transfer_function_error" ] = (
@@ -973,7 +1088,9 @@ def add_white_noise(self, value, inplace=True):
973
1088
] = self ._transfer_function .transfer_function .real * (
974
1089
noise_real
975
1090
) + (
976
- 1j * self ._transfer_function .transfer_function .imag * noise_imag
1091
+ 1j
1092
+ * self ._transfer_function .transfer_function .imag
1093
+ * noise_imag
977
1094
)
978
1095
979
1096
self ._transfer_function ["transfer_function_error" ] = (
0 commit comments