mtpy.core.transfer_function.z_analysis package

Submodules

mtpy.core.transfer_function.z_analysis.distortion module

mtpy/analysis/distortion.py

Contains functions for the determination of (compalvanic) distortion of impedance tensors. The methods used follow Bibby et al 2005. As it has been pointed out in that paper, there are various possibilities for constrainincomp the solution, esp. in the 2D case.

Here we just implement the ‘most basic’ variety for the calculation of the distortion tensor. Other methods can be implemented, but since the optimal assumptions and constraints depend on the application, the actual place for further functions is in an independent, personalised module.

Alcomporithm Details: Findincomp the distortion of a Z array. Usincomp the phase tensor so, Z arrays are transformed into PTs first), followincomp Bibby et al. 2005.

First, try to find periods that indicate 1D. From them determine D incl. the comp-factor by calculatiincomp a weicomphted mean. The comp is assumed in order to cater for the missincomp unknown in the system, it is here set to det(X)^0.5. After that is found, the function no_distortion from the Z module can be called to obtain the unperturbated recompional impedance tensor.

Second, if there are no 1D sections: Find the strike angle, then rotate the Z to the principal axis. In order to do that, use the rotate(-strike) method of the Z module. Then take the real part of the rotated Z. As in the 1D case, we need an assumption to compet rid of the (2) unknowns: set det(D) = P and det(D) = T, where P,T can be chosen. Common choice is to set one of P,T to an arbitrary value (e.comp. 1). Then check, for which values of the other parameter S^2 = T^2+4*P*X_12*X_21/det(X) > 0 holds.

@UofA, 2013 (LK)

Edited by JP, 2016

mtpy.core.transfer_function.z_analysis.distortion.find_distortion(z_object, comp: str = 'det', only_2d: bool = False, clockwise: bool = True) tuple[ndarray, ndarray][source]

Find optimal distortion tensor from impedance tensor object.

Automatically determine the dimensionality over all frequencies, then find the appropriate distortion tensor D.

Parameters:
  • z_object (mtpy.core.transfer_function.z.Z) – Impedance tensor object

  • comp (str, optional) – Component for gain calculation (“det”, “01”, or “10”), by default “det”

  • only_2d (bool, optional) – If True, treat 1D as non-distorted (set to dimension 4), by default False

  • clockwise (bool, optional) – Rotation direction for strike angle, by default True

Returns:

  • dis_avg (np.ndarray) – Average distortion tensor (2, 2)

  • dis_avg_error (np.ndarray) – Average distortion tensor error (2, 2)

Examples

>>> import mtpy.analysis.distortion as distortion
>>> dis, dis_error = distortion.find_distortion(z_object, num_freq=12)
mtpy.core.transfer_function.z_analysis.distortion.remove_distortion_from_z_object(z_object, distortion_tensor: ndarray, distortion_error_tensor: ndarray | None = None, logger=None) tuple[ndarray, ndarray][source]

Remove distortion D from an observed impedance tensor Z to obtain Z0.

The relationship is Z = D * Z0, where Z0 is the unperturbed impedance. Units should be in MT units of mV/km/nT.

Parameters:
  • z_object (mtpy.core.transfer_function.z.Z) – Impedance tensor object

  • distortion_tensor (np.ndarray) – Real distortion tensor with shape (2, 2)

  • distortion_error_tensor (np.ndarray or None, optional) – Real distortion tensor error with shape (2, 2), by default None

  • logger (logging.Logger or None, optional) – Logger for messages, by default None

Returns:

  • z_corrected (np.ndarray) – Impedance tensor with distortion removed, shape (num_frequency, 2, 2)

  • z_corrected_error (np.ndarray) – Impedance tensor error after distortion is removed, shape (num_frequency, 2, 2)

Raises:

ValueError – If distortion tensor has incorrect shape or is singular

Notes

Propagation of errors/uncertainties is included in the calculation.

mtpy.core.transfer_function.z_analysis.niblettbostick module

mtpy/mtpy/analysis/niblettbostick.py

Contains functions for the calculation of the Niblett-Bostick transformation of impedance tensors.

The methods follow:

  • Niblett

  • Bostick

  • Jones

    1. RODRIGUEZ, F.J. ESPARZA, E. GOMEZ-TREVINO

Niblett-Bostick transformations are possible in 1D and 2D.

@UofA, 2013 (LK)

Updated 2022-09 JP

mtpy.core.transfer_function.z_analysis.niblettbostick.calculate_depth_of_investigation(z_object) ndarray[source]

Determine depth-dependent Niblett-Bostick transformed impedance tensor.

Calculates Z_nb (depth dependent Niblett-Bostick transformed Z) from the 1D and 2D parts of an impedance tensor array Z.

The calculation follows 6 steps:

  1. Determine the dimensionality of Z(T), discard all 3D parts

  2. Rotate all Z(T) to TE/TM setup (T_parallel/T_ortho)

  3. Transform every component individually by Niblett-Bostick

  4. Collect the respective 2 components each for equal/similar depths

  5. Interpret them as TE_nb/TM_nb

  6. Set up Z_nb(depth)

If 1D layers occur between 2D layers, the strike angle is undefined. A linear interpolation of strike angle is used for these layers, with values varying between the angles of the bounding upper and lower 2D layers (linearly with respect to periods).

Parameters:

z_object (mtpy.core.transfer_function.z.Z) – Impedance tensor object

Returns:

Structured array with fields: period, depth_xy, depth_yx, depth_det, depth_min, depth_max, resistivity_xy, resistivity_yx, resistivity_det, resistivity_min, resistivity_max

Return type:

np.ndarray

Notes

No propagation of errors implemented yet.

Examples

>>> import mtpy.analysis.niblettbostick as nb
>>> depth_array = nb.calculate_depth_of_investigation(z_object=z1)
>>> # plot the results
>>> import matplotlib.pyplot as plt
>>> fig = plt.figure()
>>> ax = fig.add_subplot(1,1,1)
>>> ax.semilogy(depth_array['depth_min'], depth_array['period'])
>>> ax.semilogy(depth_array['depth_max'], depth_array['period'])
>>> plt.show()
mtpy.core.transfer_function.z_analysis.niblettbostick.calculate_depth_sensitivity(depth: ndarray, period: ndarray, rho: float = 100) ndarray[source]

Compute sensitivity S(z, sigma, omega) = -kz*exp(-2*kz).

The result is independent of sigma and frequency.

Parameters:
  • depth (np.ndarray) – Depth values in meters

  • period (np.ndarray) – Period values in seconds

  • rho (float, optional) – Resistivity in Ohm meters, by default 100

Returns:

Sensitivity values

Return type:

np.ndarray

mtpy.core.transfer_function.z_analysis.niblettbostick.calculate_niblett_bostick_depth(resistivity: ndarray, period: ndarray) ndarray[source]

Use the Niblett-Bostick approximation for depth of penetration.

Parameters:
  • resistivity (np.ndarray) – Resistivity values in Ohm meters

  • period (np.ndarray) – Period values in seconds

Returns:

Depth of penetration in meters

Return type:

np.ndarray

mtpy.core.transfer_function.z_analysis.niblettbostick.calculate_niblett_bostick_resistivity_derivatives(resistivity: ndarray, period: ndarray) ndarray[source]

Convert resistivity to Niblett-Bostick resistivity using derivatives.

The conversion uses derivatives of log(resistivity) vs log(period). Bostick resistivity is only valid for -1 < m < 1, where m is the gradient.

Parameters:
  • resistivity (np.ndarray) – Resistivity values in Ohm meters

  • period (np.ndarray) – Period values in seconds

Returns:

Niblett-Bostick transformed resistivity in Ohm meters

Return type:

np.ndarray

mtpy.core.transfer_function.z_analysis.niblettbostick.calculate_niblett_bostick_resistivity_weidelt(resistivity: ndarray, phase: ndarray) ndarray[source]

Convert resistivity/phase to Niblett-Bostick resistivity using Weidelt approximation.

The conversion uses the simplified transformation without derivatives.

Parameters:
  • resistivity (np.ndarray) – Resistivity values in Ohm meters

  • phase (np.ndarray) – Phase values in degrees

Returns:

Niblett-Bostick transformed resistivity in Ohm meters

Return type:

np.ndarray

mtpy.core.transfer_function.z_analysis.zinvariants module

Created on Wed May 08 09:40:42 2013

Originally written by Stephan Thiel in Matlab 2005 translated to Python by Lars Krieger

Revised by J. Peacock 2023 to fit with version 2.

class mtpy.core.transfer_function.z_analysis.zinvariants.ZInvariants(z: ndarray | None = None)[source]

Bases: object

Calculate invariants from Weaver et al. [2000, 2003].

At the moment it does not calculate the error for each invariant, only the strike.

Parameters:

z (np.ndarray or None, optional) – Impedance tensor array with shape (nf, 2, 2), by default None

z

Impedance tensor array

Type:

np.ndarray or None

References

property anisotropic_imag: ndarray | None

Anisotropic imaginary invariant (inv 4).

property anisotropic_real: ndarray | None

Anisotropic real invariant (inv 3).

property dimensionality: ndarray | None

Dimensionality parameter q.

property electric_twist: ndarray | None

Electric twist invariant (inv 5).

has_impedance() bool[source]

Check if impedance tensor contains non-zero values.

property normalizing_imag: ndarray | None

Normalizing imaginary invariant (inv 2).

property normalizing_real: ndarray | None

Normalizing real invariant (inv 1).

property phase_distortion: ndarray | None

Phase distortion invariant (inv 6).

property strike: ndarray | None

Strike angle in degrees.

property strike_error: ndarray | None

Strike angle error in degrees.

property structure_3d: ndarray | None

3D structure invariant (inv 7).

Module contents

class mtpy.core.transfer_function.z_analysis.ZInvariants(z: ndarray | None = None)[source]

Bases: object

Calculate invariants from Weaver et al. [2000, 2003].

At the moment it does not calculate the error for each invariant, only the strike.

Parameters:

z (np.ndarray or None, optional) – Impedance tensor array with shape (nf, 2, 2), by default None

z

Impedance tensor array

Type:

np.ndarray or None

References

property anisotropic_imag: ndarray | None

Anisotropic imaginary invariant (inv 4).

property anisotropic_real: ndarray | None

Anisotropic real invariant (inv 3).

property dimensionality: ndarray | None

Dimensionality parameter q.

property electric_twist: ndarray | None

Electric twist invariant (inv 5).

has_impedance() bool[source]

Check if impedance tensor contains non-zero values.

property normalizing_imag: ndarray | None

Normalizing imaginary invariant (inv 2).

property normalizing_real: ndarray | None

Normalizing real invariant (inv 1).

property phase_distortion: ndarray | None

Phase distortion invariant (inv 6).

property strike: ndarray | None

Strike angle in degrees.

property strike_error: ndarray | None

Strike angle error in degrees.

property structure_3d: ndarray | None

3D structure invariant (inv 7).

mtpy.core.transfer_function.z_analysis.calculate_depth_of_investigation(z_object) ndarray[source]

Determine depth-dependent Niblett-Bostick transformed impedance tensor.

Calculates Z_nb (depth dependent Niblett-Bostick transformed Z) from the 1D and 2D parts of an impedance tensor array Z.

The calculation follows 6 steps:

  1. Determine the dimensionality of Z(T), discard all 3D parts

  2. Rotate all Z(T) to TE/TM setup (T_parallel/T_ortho)

  3. Transform every component individually by Niblett-Bostick

  4. Collect the respective 2 components each for equal/similar depths

  5. Interpret them as TE_nb/TM_nb

  6. Set up Z_nb(depth)

If 1D layers occur between 2D layers, the strike angle is undefined. A linear interpolation of strike angle is used for these layers, with values varying between the angles of the bounding upper and lower 2D layers (linearly with respect to periods).

Parameters:

z_object (mtpy.core.transfer_function.z.Z) – Impedance tensor object

Returns:

Structured array with fields: period, depth_xy, depth_yx, depth_det, depth_min, depth_max, resistivity_xy, resistivity_yx, resistivity_det, resistivity_min, resistivity_max

Return type:

np.ndarray

Notes

No propagation of errors implemented yet.

Examples

>>> import mtpy.analysis.niblettbostick as nb
>>> depth_array = nb.calculate_depth_of_investigation(z_object=z1)
>>> # plot the results
>>> import matplotlib.pyplot as plt
>>> fig = plt.figure()
>>> ax = fig.add_subplot(1,1,1)
>>> ax.semilogy(depth_array['depth_min'], depth_array['period'])
>>> ax.semilogy(depth_array['depth_max'], depth_array['period'])
>>> plt.show()
mtpy.core.transfer_function.z_analysis.find_distortion(z_object, comp: str = 'det', only_2d: bool = False, clockwise: bool = True) tuple[ndarray, ndarray][source]

Find optimal distortion tensor from impedance tensor object.

Automatically determine the dimensionality over all frequencies, then find the appropriate distortion tensor D.

Parameters:
  • z_object (mtpy.core.transfer_function.z.Z) – Impedance tensor object

  • comp (str, optional) – Component for gain calculation (“det”, “01”, or “10”), by default “det”

  • only_2d (bool, optional) – If True, treat 1D as non-distorted (set to dimension 4), by default False

  • clockwise (bool, optional) – Rotation direction for strike angle, by default True

Returns:

  • dis_avg (np.ndarray) – Average distortion tensor (2, 2)

  • dis_avg_error (np.ndarray) – Average distortion tensor error (2, 2)

Examples

>>> import mtpy.analysis.distortion as distortion
>>> dis, dis_error = distortion.find_distortion(z_object, num_freq=12)
mtpy.core.transfer_function.z_analysis.remove_distortion_from_z_object(z_object, distortion_tensor: ndarray, distortion_error_tensor: ndarray | None = None, logger=None) tuple[ndarray, ndarray][source]

Remove distortion D from an observed impedance tensor Z to obtain Z0.

The relationship is Z = D * Z0, where Z0 is the unperturbed impedance. Units should be in MT units of mV/km/nT.

Parameters:
  • z_object (mtpy.core.transfer_function.z.Z) – Impedance tensor object

  • distortion_tensor (np.ndarray) – Real distortion tensor with shape (2, 2)

  • distortion_error_tensor (np.ndarray or None, optional) – Real distortion tensor error with shape (2, 2), by default None

  • logger (logging.Logger or None, optional) – Logger for messages, by default None

Returns:

  • z_corrected (np.ndarray) – Impedance tensor with distortion removed, shape (num_frequency, 2, 2)

  • z_corrected_error (np.ndarray) – Impedance tensor error after distortion is removed, shape (num_frequency, 2, 2)

Raises:

ValueError – If distortion tensor has incorrect shape or is singular

Notes

Propagation of errors/uncertainties is included in the calculation.