Skip to content

Commit 474f342

Browse files
committed
updating how z units are propagated
1 parent 4f0eec1 commit 474f342

File tree

5 files changed

+83
-24
lines changed

5 files changed

+83
-24
lines changed

mtpy/core/mt.py

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
Z,
1919
Tipper,
2020
COORDINATE_REFERENCE_FRAME_OPTIONS,
21+
MT_TO_OHM_FACTOR,
22+
IMPEDANCE_UNITS,
2123
)
2224
from mtpy.core.mt_location import MTLocation
2325
from mtpy.core.mt_dataframe import MTDataFrame
@@ -78,7 +80,7 @@ class MT(TF, MTLocation):
7880
7981
"""
8082

81-
def __init__(self, fn=None, **kwargs):
83+
def __init__(self, fn=None, impedance_units="mt", **kwargs):
8284
tf_kwargs = {}
8385
for key in [
8486
"period",
@@ -117,6 +119,9 @@ def __init__(self, fn=None, **kwargs):
117119
self.station_metadata.transfer_function.sign_convention
118120
)
119121

122+
self._impedance_unit_factors = IMPEDANCE_UNITS
123+
self.impedance_units = impedance_units
124+
120125
for key, value in kwargs.items():
121126
setattr(self, key, value)
122127

@@ -215,6 +220,23 @@ def coordinate_reference_frame(self, value):
215220

216221
self.station_metadata.transfer_function.sign_convention = value
217222

223+
@property
224+
def impedance_units(self):
225+
"""impedance units"""
226+
return self._impedance_units
227+
228+
@impedance_units.setter
229+
def impedance_units(self, value):
230+
"""impedance units setter options are [ mt | ohm ]"""
231+
if not isinstance(value, str):
232+
raise TypeError("Units input must be a string.")
233+
if value.lower() not in self._impedance_unit_factors.keys():
234+
raise ValueError(
235+
f"{value} is not an acceptable unit for impedance."
236+
)
237+
238+
self._impedance_units = value
239+
218240
@property
219241
def rotation_angle(self):
220242
"""Rotation angle in degrees from north. In the coordinate reference frame"""
@@ -291,6 +313,7 @@ def Z(self):
291313
z_error=self.impedance_error.to_numpy(),
292314
frequency=self.frequency,
293315
z_model_error=self.impedance_model_error.to_numpy(),
316+
units=self.impedance_units,
294317
)
295318
return Z()
296319

@@ -301,6 +324,9 @@ def Z(self, z_object):
301324
recalculate phase tensor and invariants, which shouldn't change except
302325
for strike angle.
303326
"""
327+
# if a z object is given the underlying data is in mt units, even
328+
# if the units are set to ohm.
329+
z_object.units = "mt"
304330
if not isinstance(z_object.frequency, type(None)):
305331
if self.frequency.size != z_object.frequency.size:
306332
self.frequency = z_object.frequency
@@ -638,7 +664,7 @@ def plot_depth_of_penetration(self, **kwargs):
638664

639665
return PlotPenetrationDepth1D(self, **kwargs)
640666

641-
def to_dataframe(self, utm_crs=None, cols=None):
667+
def to_dataframe(self, utm_crs=None, cols=None, impedance_units="mt"):
642668
"""Create a dataframe from the transfer function for use with plotting
643669
and modeling.
644670
:param cols:
@@ -648,6 +674,8 @@ def to_dataframe(self, utm_crs=None, cols=None):
648674
:param eter utm_crs: The utm zone to project station to, could be a
649675
name, pyproj.CRS, EPSG number, or anything that pyproj.CRS can intake.
650676
:type eter utm_crs: string, int, :class:`pyproj.CRS`
677+
:param impedance_units: ["mt" [mV/km/nT] | "ohm" [Ohms] ]
678+
:type impedance_units: str
651679
"""
652680
if utm_crs is not None:
653681
self.utm_crs = utm_crs
@@ -671,19 +699,22 @@ def to_dataframe(self, utm_crs=None, cols=None):
671699

672700
mt_df.dataframe.loc[:, "period"] = self.period
673701
if self.has_impedance():
674-
mt_df.from_z_object(self.Z)
702+
z_object = self.Z
703+
z_object.units = impedance_units
704+
mt_df.from_z_object(z_object)
705+
mt_df.from_z_object(z_object)
675706
if self.has_tipper():
676707
mt_df.from_t_object(self.Tipper)
677708

678709
return mt_df
679710

680-
def from_dataframe(self, mt_df):
711+
def from_dataframe(self, mt_df, impedance_units="mt"):
681712
"""Fill transfer function attributes from a dataframe for a single station.
682713
:param mt_df:
683714
:param df: DESCRIPTION.
684715
:type df: TYPE
685-
:return: DESCRIPTION.
686-
:rtype: TYPE
716+
:param impedance_units: ["mt" [mV/km/nT] | "ohm" [Ohms] ]
717+
:type impedance_units: str
687718
"""
688719

689720
if not isinstance(mt_df, MTDataFrame):
@@ -717,11 +748,9 @@ def from_dataframe(self, mt_df):
717748

718749
self.tf_id = self.station
719750

720-
# self._transfer_function = self._initialize_transfer_function(
721-
# mt_df.period
722-
# )
723-
724-
self.Z = mt_df.to_z_object()
751+
z_obj = mt_df.to_z_object()
752+
z_obj.units = impedance_units
753+
self.Z = z_obj
725754
self.Tipper = mt_df.to_t_object()
726755

727756
def compute_model_z_errors(

mtpy/core/transfer_function/base.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,11 @@ def __eq__(self, other):
102102

103103
# loop over variables to make sure they are all the same.
104104
for var in list(self._dataset.data_vars):
105-
if not (self._dataset[var] == other._dataset[var]).all().data:
106-
return False
105+
try:
106+
if not (self._dataset[var] == other._dataset[var]).all().data:
107+
return False
108+
except TypeError:
109+
continue
107110
return True
108111

109112
def __deepcopy__(self, memo):
@@ -164,9 +167,7 @@ def _initialize(
164167
tf_error = np.zeros_like(
165168
tf_model_error, dtype=self._tf_dtypes["tf_error"]
166169
)
167-
periods = self._validate_frequency(
168-
periods, tf_model_error.shape[0]
169-
)
170+
periods = self._validate_frequency(periods, tf_model_error.shape[0])
170171

171172
else:
172173
periods = self._validate_frequency(periods)

mtpy/core/transfer_function/z.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ def __init__(
7777
7878
"""
7979

80+
self._ohm_factor = MT_TO_OHM_FACTOR
81+
self._unit_factors = IMPEDANCE_UNITS
82+
self.units = units
83+
84+
# if units input is ohms, then we want to scale them to mt units that
85+
# way the underlying data is consistent in [mV/km/nT]
86+
if z is not None:
87+
z = z * self._scale_factor
88+
if z_error is not None:
89+
z_error = z_error * self._scale_factor
90+
if z_model_error is not None:
91+
z_model_error = z_model_error * self._scale_factor
92+
8093
super().__init__(
8194
tf=z,
8295
tf_error=z_error,
@@ -85,10 +98,6 @@ def __init__(
8598
_name="impedance",
8699
)
87100

88-
self._ohm_factor = MT_TO_OHM_FACTOR
89-
self._unit_factors = IMPEDANCE_UNITS
90-
self.units = units
91-
92101
@property
93102
def units(self):
94103
"""impedance units"""
@@ -122,7 +131,7 @@ def z(self):
122131

123132
@z.setter
124133
def z(self, z):
125-
"""Set the attribute 'z'.
134+
"""Set the attribute 'z'. Should be in units of mt [mV/km/nT]
126135
:param z: Complex impedance tensor array.
127136
:type z: np.ndarray(nfrequency, 2, 2)
128137
"""

tests/core/test_mt.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,7 @@ def setUpClass(self):
100100
[[[35.26438968, 0.20257033], [0.20257033, 35.26438968]]]
101101
)
102102

103-
self.pt = np.array(
104-
[[[1.00020002, -0.020002], [-0.020002, 1.00020002]]]
105-
)
103+
self.pt = np.array([[[1.00020002, -0.020002], [-0.020002, 1.00020002]]])
106104
self.pt_error = np.array(
107105
[[[0.01040308, 0.02020604], [0.02020604, 0.01040308]]]
108106
)
@@ -367,6 +365,25 @@ def test_from_dataframe_fail(self):
367365
self.assertRaises(TypeError, self.m1.from_dataframe, "a")
368366

369367

368+
class TestMT2DataFrameOhms(unittest.TestCase):
369+
@classmethod
370+
def setUpClass(self):
371+
self.m1 = MT(TF_EDI_CGG)
372+
self.m1.read()
373+
374+
self.mt_df = self.m1.to_dataframe(impedance_units="ohm")
375+
376+
def test_impedance_in_ohms(self):
377+
z_obj = self.m1.Z
378+
z_obj.units = "ohm"
379+
380+
self.assertEqual(z_obj, self.mt_df.to_z_object())
381+
382+
def test_impedance_not_equal(self):
383+
384+
self.assertNotEqual(self.m1.Z, self.mt_df.to_z_object())
385+
386+
370387
# =============================================================================
371388
# Run
372389
# =============================================================================

tests/core/transfer_function/test_z.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ def test_resistivity_model_error(self):
6262
def test_phase_model_error(self):
6363
self.assertEqual(None, self.z.phase_model_error)
6464

65+
def test_units(self):
66+
self.assertEqual("mt", self.z.units)
67+
6568

6669
class TestZSetResPhase(unittest.TestCase):
6770
"""

0 commit comments

Comments
 (0)