pycsamt.z.tipper#
Tipper
Classes
|
Induction tipper container with derived quantities. |
- class pycsamt.z.tipper.Tipper(tipper_array=None, tipper_err_array=None, freq=None, *, name=None, **kw)[source]#
Bases:
EMBaseInduction tipper container with derived quantities.
The class stores complex tipper components \((T_x, T_y)\) per frequency and provides convenience computations:
amplitude / phase of each component
Parkinson induction arrows (magnitude and direction) for real and imaginary parts
rotation of the tipper with optional error propagation
Internally, data are kept with shape
(n_freq, 1, 2)where the last axis is ordered as[T_x, T_y]. Several common input shapes are accepted and normalized on assignment.- Parameters:
tipper_array (array-like, optional) –
Complex tipper values. Accepted shapes:
(n_freq, 1, 2)(preferred)(n_freq, 2)(promoted)(2,)or(1, 2)(single row)
The last axis is ordered as
[T_x, T_y].tipper_err_array (array-like, optional) – Absolute errors with the same normalized shape as
tipper_array. IfNone, uncertainties are not propagated.freq (array-like of float, optional) – Frequency vector in Hz. Length must be
n_freqand values strictly positive.name (str | None)
kw (Any)
- Variables:
tipper (ndarray or None) – Complex tipper, shape
(n_freq, 1, 2).tipper_err (ndarray or None) – Absolute errors on :pyattr:`tipper`.
freq (ndarray or None) – Frequency vector (Hz).
rotation_angle (float or ndarray) – Cumulative rotation (deg, clockwise positive). Stored as a scalar or length
n_freqvector.phase (amplitude,) – \(|T|\) and phase (deg) for each component. Shape
(n_freq, 1, 2).phase_err (amplitude_err,) – Propagated absolute amplitude error and absolute phase error (deg), or
None.mag_imag (mag_real,) – Parkinson arrow magnitudes built from the real and imaginary parts, shape
(n_freq,).angle_imag (angle_real,) – Parkinson arrow directions (deg), real and imag, shape
(n_freq,).angle_err (mag_err,) – Heuristic uncertainty proxies for arrow metrics, or
None.
Notes
Shape normalization. Inputs with shape
(n_freq, 2)or(2,)are promoted to(n_freq, 1, 2). Errors follow the same rules.Parkinson convention. Arrow directions use a minus sign so arrows point towards conductors:
\[\theta = \operatorname{atan2}(-Y,\,-X)\]where \((X, Y)\) are the component pairs taken from either the real or the imaginary part.
Rotation. Angles are clockwise-positive and referenced to geographic North (X→North, Y→East).
Examples
Minimal construction and amplitude / phase:
>>> import numpy as np >>> from pycsamt.z.tipper import Tipper >>> T = np.array([[1+1j, 0+1j]]) >>> tip = Tipper(tipper_array=T) # (1, 2) >>> tip.amplitude.shape, tip.phase.shape ((1, 1, 2), (1, 1, 2))
Parkinson arrows for a known direction:
>>> th = np.deg2rad(30.0) >>> Tarr = np.zeros((1, 1, 2), complex) >>> Tarr[0, 0, 0] = -np.cos(th) + 0j >>> Tarr[0, 0, 1] = -np.sin(th) + 0j >>> tip = Tipper(tipper_array=Tarr) >>> float(tip.mag_real[0]) 1.0 >>> float(tip.angle_real[0]) 30.0
See also
pycsamt.utils.zmath.rotatevector_incl_errorsRotation with error propagation.
pycsamt.z.base.BaseEMShared container utilities.
References
- compute_amp_phase()[source]#
Compute \(|T|\) and phase (deg) for each component.
For every frequency and for both components \((T_x, T_y)\), the amplitude is \(|T| = \sqrt{(\Re T)^2 + (\Im T)^2}\) and the phase is the argument of the complex number in degrees.
When :pyattr:`tipper_err` is present, uncertainties are propagated component-wise using
pycsamt.utils.zmath.propagate_error_rect2polar().- Returns:
Results are stored in the attributes :pyattr:`amplitude`, :pyattr:`phase`, and, when applicable, :pyattr:`amplitude_err`, :pyattr:`phase_err`.
- Return type:
None
Notes
If :pyattr:`tipper` is
None, the method exits silently and leaves derived fields unchanged.Examples
>>> import numpy as np >>> from pycsamt.z.tipper import Tipper >>> T = np.array([[[1+1j, 0+1j]]]) >>> tip = Tipper(tipper_array=T) >>> tip.compute_amp_phase() >>> tip.amplitude.shape, tip.phase.shape ((1, 1, 2), (1, 1, 2))
- compute_mag_direction()[source]#
Compute Parkinson arrow magnitudes and directions.
Real-part arrow:
\[M_{\Re} = \sqrt{(\Re T_x)^2 + (\Re T_y)^2}\]\[\theta_{\Re} = \operatorname{atan2}(-\Re T_y,\,-\Re T_x)\]Imag-part arrow is computed identically, using \(\Im T_x\) and \(\Im T_y\).
The minus sign makes arrows point towards conductors (Parkinson convention).
- Returns:
Results are stored in :pyattr:`mag_real`, :pyattr:`mag_imag`, :pyattr:`angle_real`, :pyattr:`angle_imag`. If :pyattr:`tipper_err` is present, heuristic proxies :pyattr:`mag_err` and :pyattr:`angle_err` are also set.
- Return type:
None
Notes
Angle uncertainties are estimated via a bounded small-angle proxy and wrapped within a legacy 45° cap.
Examples
>>> import numpy as np >>> from pycsamt.z.tipper import Tipper >>> th = np.deg2rad(60.0) >>> Tarr = np.zeros((1, 1, 2), complex) >>> Tarr[0, 0, 0] = 0.0 + 1j*(-np.cos(th)) >>> Tarr[0, 0, 1] = 0.0 + 1j*(-np.sin(th)) >>> tip = Tipper(tipper_array=Tarr) >>> float(tip.angle_imag[0]) 60.0
- set_amp_phase(r_array, phi_array)[source]#
Set tipper from amplitude \(r\) and phase \(\phi\).
Converts the provided real arrays to complex tipper values via
\[T = r \, e^{j \, \phi},\]where \(\phi\) is given in degrees. Shapes are normalized to
(n_freq, 1, 2)following the same rules as :pyattr:`tipper`.- Parameters:
r_array (array-like) – Real amplitudes. Accepted shapes are the same as for :pyattr:`tipper`. Must be real-valued.
phi_array (array-like) – Real phases in degrees. Same shape rules as
r_array.
- Raises:
ZError – If shapes are incompatible or inputs are not real after normalization.
- Returns:
The method updates :pyattr:`tipper` and then recomputes amplitude / phase and arrow metrics.
- Return type:
None
Notes
If :pyattr:`tipper` already exists, both arrays must match its normalized shape.
Examples
>>> import numpy as np >>> from pycsamt.z.tipper import Tipper >>> r = np.ones((2, 1, 2)) >>> phi = np.zeros_like(r) >>> phi[:, 0, 1] = 90.0 >>> tip = Tipper() >>> tip.set_amp_phase(r, phi) >>> tip.tipper.shape (2, 1, 2)
- set_mag_direction(mag_real, ang_real, mag_imag, ang_imag)[source]#
Set tipper from Parkinson magnitudes and directions.
For each frequency, reconstruct components per the Parkinson convention:
\[T_x = -M \cos\theta,\quad T_y = -M \sin\theta,\]applied separately to the real and the imaginary parts. Angles are provided in degrees.
- Parameters:
mag_real (array-like) – Arrow magnitudes for the real and imaginary parts. Scalar or length
n_freq.mag_imag (array-like) – Arrow magnitudes for the real and imaginary parts. Scalar or length
n_freq.ang_real (array-like) – Arrow directions (deg) for real and imaginary parts. Scalar or length
n_freq.ang_imag (array-like) – Arrow directions (deg) for real and imaginary parts. Scalar or length
n_freq.
- Raises:
ZError – If :pyattr:`tipper` is not initialized or if the supplied vectors are not scalar or length
n_freq.- Returns:
The method updates :pyattr:`tipper` and then recomputes arrow metrics and amplitude / phase.
- Return type:
None
Examples
>>> import numpy as np >>> from pycsamt.z.tipper import Tipper >>> tip = Tipper(tipper_array=np.zeros((1, 1, 2), complex)) >>> tip.set_mag_direction(1.0, 0.0, 2.0, 90.0) >>> tuple(np.round(tip.tipper[0, 0].real, 6)) (-1.0, -0.0)
- rotate(alpha)[source]#
Rotate tipper(s) clockwise by the given angle(s).
Angles are referenced to geographic North (X→North, Y→East). Positive angles are clockwise.
- Parameters:
alpha (float or sequence of float) – Single angle applied to all frequencies, or a length
n_freqsequence of angles (deg).- Raises:
ZError – If :pyattr:`tipper` is missing, or if the number of angles is not 1 or
n_freq.- Returns:
The method updates :pyattr:`tipper`, :pyattr:`tipper_err` (if present), and :pyattr:`rotation_angle`, then recomputes amplitude / phase and arrow metrics.
- Return type:
None
Notes
Error propagation uses
pycsamt.utils.zmath.rotatevector_incl_errors(). Angles are reduced modulo 360° in the rotation history.Examples
>>> import numpy as np >>> from pycsamt.z.tipper import Tipper >>> T = np.array([[[1.0+0.0j, 0.0+0.0j]]]) >>> tip = Tipper(tipper_array=T) >>> tip.rotate(90.0) >>> np.allclose(tip.rotation_angle, 90.0) True