Example #1
0
def strike_angle(z_array=None, z_object=None, pt_array=None,
                 pt_object=None, skew_threshold=5,
                 eccentricity_threshold=0.1):
    """
    Estimate strike angle from 2D parts of the impedance tensor given the
    skew and eccentricity thresholds

        Arguments
    ------------

        **z_array** : np.ndarray(nf, 2, 2)
                      numpy array of impedance elements
                      *default* is None

        **z_object** : mtpy.core.z.Z
                       z_object
                       *default* is None

        **pt_array** : np.ndarray(nf, 2, 2)
                       numpy array of phase tensor elements
                       *default* is None

        **pt_object** : mtpy.analysis.pt.PT
                        phase tensor object
                        *default* is None

        **skew_threshold** : float
                             threshold on the skew angle in degrees, anything
                             above this value is 3-D or azimuthally anisotropic
                             *default* is 5 degrees

        **eccentricity_threshold** : float
                                     threshold on eccentricty in dimensionaless
                                     units, anything below this value is 1-D
                                     *default* is 0.1

    Returns
    ----------

        **strike** : np.ndarray(nf)
                         an array of strike angles in degrees for each frequency
                         assuming 0 is north, and e is 90.  There is a 90
                         degree ambiguity in the angle.


    Examples
    ----------
        :Estimate Dimesions: ::

            >>> import mtpy.analysis.geometry as geometry
            >>> strike = geometry.strike_angle(z_object=z_obj,
            >>>                                skew_threshold=3)

    """

    if z_array is not None:
        pt_obj = MTpt.PhaseTensor(z_array=z_array)
    elif z_object is not None:
        if not isinstance(z_object, MTz.Z):
            raise MTex.MTpyError_Z(
                'Input argument is not an instance of the Z class')
        pt_obj = MTpt.PhaseTensor(z_object=z_object)

    elif pt_array is not None:
        pt_obj = MTpt.PhaseTensor(pt_array=pt_array)
    elif pt_object is not None:
        if not isinstance(pt_object, MTpt.PhaseTensor):
            raise MTex.MTpyError_PT(
                'Input argument is not an instance of the PhaseTensor class')
        pt_obj = pt_object

    lo_dims = dimensionality(pt_object=pt_obj,
                             skew_threshold=skew_threshold,
                             eccentricity_threshold=eccentricity_threshold)

    lo_strikes = []

    for idx, dim in enumerate(lo_dims):
        if dim == 1:
            lo_strikes.append((np.nan, np.nan))
            continue

        a = pt_obj.alpha[idx]
        b = pt_obj.beta[idx]

        strike1 = (a - b) % 90
        if 0 < strike1 < 45:
            strike2 = strike1 + 90
        else:
            strike2 = strike1 - 90

        s1 = min(strike1, strike2)
        s2 = max(strike1, strike2)

        lo_strikes.append((s1, s2))

    return np.array(lo_strikes)
Example #2
0
def eccentricity(z_array=None, z_object=None, pt_array=None, pt_object=None):
    """
    Estimate eccentricy of a given impedance or phase tensor object
    
    
    Arguments
    ------------
    
        **z_array** : np.ndarray(nf, 2, 2)
                      numpy array of impedance elements
                      *default* is None
                      
        **z_object** : mtpy.core.z.Z 
                       z_object
                       *default* is None
                       
        **pt_array** : np.ndarray(nf, 2, 2)
                       numpy array of phase tensor elements
                       *default* is None
                       
        **pt_object** : mtpy.analysis.pt.PT
                        phase tensor object
                        *default* is None

                                     
    Returns
    ----------
    
        **eccentricity** : np.ndarray(nf)
        
        
        **eccentricity_err** : np.ndarray(nf)
                            
                         
                         
    Examples
    ----------
        :Estimate Dimesions: ::
        
            >>> import mtpy.analysis.geometry as geometry
            >>> ec, ec_err= geometry.eccentricity(z_object=z_obj)
    """

    if z_array is not None:
        pt_obj = MTpt.PhaseTensor(z_array=z_array)
    elif z_object is not None:
        if not isinstance(z_object, MTz.Z):
            raise MTex.MTpyError_Z(
                'Input argument is not an instance of the Z class')
        pt_obj = MTpt.PhaseTensor(z_object=z_object)
    elif pt_array is not None:
        pt_obj = MTpt.PhaseTensor(pt_array=pt_array)
    elif pt_object is not None:
        if not isinstance(pt_object, MTpt.PhaseTensor):
            raise MTex.MTpyError_PT(
                'Input argument is not an instance of the PhaseTensor class')
        pt_obj = pt_object

    lo_ecc = []
    lo_eccerr = []

    if not isinstance(pt_obj, MTpt.PhaseTensor):
        raise MTex.MTpyError_PT(
            'Input argument is not an instance of the PhaseTensor class')

    for idx_f in range(len(pt_obj.pt)):
        lo_ecc.append(pt_obj._pi1()[0][idx_f] / pt_obj._pi2()[0][idx_f])

        ecc_err = None
        if (pt_obj._pi1()[1] is not None) and (pt_obj._pi2()[1] is not None):
            ecc_err = np.sqrt(
                (pt_obj._pi1()[1][idx_f] / pt_obj._pi1()[0][idx_f])**2 +
                (pt_obj._pi2()[1][idx_f] / pt_obj._pi2()[0][idx_f])**2)

        lo_eccerr.append(ecc_err)

    return np.array(lo_ecc), np.array(lo_eccerr)
Example #3
0
def dimensionality(z_array=None,
                   z_object=None,
                   pt_array=None,
                   pt_object=None,
                   skew_threshold=5,
                   eccentricity_threshold=0.1):
    """
    Esitmate dimensionality of an impedance tensor, frequency by frequency.

    Dimensionality is estimated from the phase tensor given the threshold
    criteria on the skew angle and eccentricity following Bibby et al., 2005
    and Booker, 2014.
    
    Arguments
    ------------
    
        **z_array** : np.ndarray(nf, 2, 2)
                      numpy array of impedance elements
                      *default* is None
                      
        **z_object** : mtpy.core.z.Z 
                       z_object
                       *default* is None
                       
        **pt_array** : np.ndarray(nf, 2, 2)
                       numpy array of phase tensor elements
                       *default* is None
                       
        **pt_object** : mtpy.analysis.pt.PT
                        phase tensor object
                        *default* is None
                        
        **skew_threshold** : float
                             threshold on the skew angle in degrees, anything
                             above this value is 3-D or azimuthally anisotropic
                             *default* is 5 degrees
                             
        **eccentricity_threshold** : float
                                     threshold on eccentricty in dimensionaless
                                     units, anything below this value is 1-D
                                     *default* is 0.1
                                     
    Returns
    ----------
    
        **dimensions** : np.ndarray(nf, dtype=int)
                         an array of dimesions for each frequency
                         the values are [ 1 | 2 | 3 ]
                         
                         
    Examples
    ----------
        :Estimate Dimesions: ::
        
            >>> import mtpy.analysis.geometry as geometry
            >>> dim = geometry.dimensionality(z_object=z_obj, 
            >>>                               skew_threshold=3)
    

    """

    lo_dimensionality = []

    if z_array is not None:
        pt_obj = MTpt.PhaseTensor(z_array=z_array)
    elif z_object is not None:
        if not isinstance(z_object, MTz.Z):
            raise MTex.MTpyError_Z(
                'Input argument is not an instance of the Z class')
        pt_obj = MTpt.PhaseTensor(z_object=z_object)
    elif pt_array is not None:
        pt_obj = MTpt.PhaseTensor(pt_array=pt_array)
    elif pt_object is not None:
        if not isinstance(pt_object, MTpt.PhaseTensor):
            raise MTex.MTpyError_PT(
                'Input argument is not an instance of the PhaseTensor class')
        pt_obj = pt_object

    # use criteria from Bibby et al. 2005 for determining the dimensionality
    # for each frequency of the pt/z array:
    for idx_f in range(len(pt_obj.pt)):
        #1. determine skew value...
        skew = pt_obj.beta[idx_f]
        #compare with threshold for 3D
        if skew > skew_threshold:
            lo_dimensionality.append(3)
        else:
            #2.check for eccentricity:
            ecc = pt_obj._pi1()[0][idx_f] / pt_obj._pi2()[0][idx_f]
            if ecc > eccentricity_threshold:
                lo_dimensionality.append(2)
            else:
                lo_dimensionality.append(1)

    return np.array(lo_dimensionality)
Example #4
0
def z2pt(z_array, z_err_array = None):
    """
        Calculate Phase Tensor from Z array (incl. uncertainties)

        Input:
        - Z : 2x2 complex valued Numpy array

        Optional:
        - Z-error : 2x2 real valued Numpy array

        Return:
        - PT : 2x2 real valued Numpy array
        - PT-error : 2x2 real valued Numpy array

    """
    if z_array is not None:
        try:
            if not  len(z_array.shape) in [2,3]:
                raise
            if not z_array.shape[-2:] == (2,2):
                raise
            if not z_array.dtype in ['complex', 'float']:
                raise
        except:
            raise MTex.MTpyError_PT('Error - incorrect z array: %s;%s instead of (N,2,2);complex'%(str(z_array.shape), str(z_array.dtype)))    


    if z_err_array is not None:
        try:
            if not  len(z_err_array.shape) in [2,3]:
                raise
            if not z_err_array.shape[-2:] == (2,2):
                raise
            if not z_err_array.dtype in ['float']:
                raise
        except:
            raise MTex.MTpyError_PT('Error - incorrect z-err-array: %s;%s instead of (N,2,2);real'%(str(z_err_array.shape), str(z_err_array.dtype)))

        if not z_array.shape == z_err_array.shape:
            raise MTex.MTpyError_PT('Error - z-array and z-err-array have different shape: %s;%s'%(str(z_array.shape), str(z_err_array.shape)))

    #for a single matrix as input:
    if len(z_array.shape) == 2:

        pt_array = np.zeros((2,2))

        realz = np.real(z_array)
        imagz = np.imag(z_array)
        detreal = np.linalg.det(realz)

        if detreal == 0 :
            if np.linalg.norm(realz) == 0 and np.linalg.norm(imagz) == 0:
                pt_err_array = np.zeros_like(pt_array)
                if z_err_array is None:
                    pt_err_array = None                
                return pt_array, pt_err_array

            else:
                raise MTex.MTpyError_PT('Error - z-array contains a singular matrix, thus it cannot be converted into a PT!' )



        pt_array[0,0] =  realz[1,1] * imagz[0,0] - realz[0,1] * imagz[1,0] 
        pt_array[0,1] =  realz[1,1] * imagz[0,1] - realz[0,1] * imagz[1,1] 
        pt_array[1,0] =  realz[0,0] * imagz[1,0] - realz[1,0] * imagz[0,0] 
        pt_array[1,1] =  realz[0,0] * imagz[1,1] - realz[1,0] * imagz[0,1] 

        pt_array /= detreal

        if z_err_array is None:
            return pt_array, None

        pt_err_array = np.zeros_like(pt_array)

        #Z entries are independent -> use Gaussian error propagation (squared sums/2-norm)
        pt_err_array[0,0] = 1/np.abs(detreal) * np.sqrt(np.sum([np.abs(-pt_array[0,0] * realz[1,1] * z_err_array[0,0])**2,
                                                                np.abs( pt_array[0,0] * realz[0,1] * z_err_array[1,0])**2,
                                                                np.abs(((imagz[0,0] * realz[1,0] - realz[0,0] * imagz[1,0]) / np.abs(detreal) * realz[0,0] ) * z_err_array[0,1])**2, 
                                                                np.abs(((imagz[1,0] * realz[0,0] - realz[1,0] * imagz[1,1]) / np.abs(detreal) * realz[0,1] ) * z_err_array[1,1])**2,
                                                                np.abs(realz[1,1] * z_err_array[0,0])**2,
                                                                np.abs(realz[0,1] * z_err_array[1,0])**2 ]))


        pt_err_array[0,1] = 1/np.abs(detreal) * np.sqrt( np.sum([np.abs( -pt_array[0,1] * realz[1,1] * z_err_array[0,0])**2,
                                                                np.abs(  pt_array[0,1] * realz[0,1] * z_err_array[1,0])**2,
                                                                np.abs(  ( (imagz[0,1] * realz[1,0] - realz[0,0] * imagz[1,1]) / np.abs(detreal) * realz[1,1] ) * z_err_array[0,1])**2, 
                                                                np.abs(  ( (imagz[1,1] * realz[0,0] - realz[0,1] * imagz[1,0]) / np.abs(detreal) * realz[0,1] ) * z_err_array[1,1])**2,
                                                                np.abs(  realz[1,1] * z_err_array[0,1])**2,
                                                                np.abs( realz[0,1] * z_err_array[1,1])**2 ]))

        pt_err_array[1,0] = 1/np.abs(detreal) * np.sqrt( np.sum([np.abs(  pt_array[1,0] * realz[1,0] * z_err_array[0,1])**2,
                                                                np.abs( -pt_array[1,0] * realz[0,0] * z_err_array[1,1])**2,
                                                                np.abs(  ( (imagz[0,0] * realz[1,1] - realz[0,1] * imagz[1,1]) / np.abs(detreal) * realz[1,0] ) * z_err_array[0,0])**2, 
                                                                np.abs(  ( (imagz[1,0] * realz[0,1] - realz[1,1] * imagz[0,0]) / np.abs(detreal) * realz[0,0] ) * z_err_array[0,1])**2,
                                                                np.abs(  realz[1,0] * z_err_array[0,0])**2,
                                                                np.abs( realz[0,0] * z_err_array[1,0])**2 ]))


        pt_err_array[1,1] = 1/np.abs(detreal) * np.sqrt( np.sum([np.abs(  pt_array[1,1] * realz[1,0] * z_err_array[0,1])**2,
                                                                np.abs( -pt_array[1,1] * realz[0,0] * z_err_array[1,1])**2,
                                                                np.abs(  ( (imagz[0,1] * realz[1,1] - realz[0,1] * imagz[1,1]) / np.abs(detreal) * realz[1,0] ) * z_err_array[0,0])**2, 
                                                                np.abs(  ( (imagz[1,1] * realz[0,1] - realz[1,1] * imagz[0,1]) / np.abs(detreal) * realz[0,0] ) * z_err_array[0,1])**2,
                                                                np.abs( - realz[1,0] * z_err_array[0,1])**2,
                                                                np.abs( realz[0,0] * z_err_array[1,1])**2 ]))


        return pt_array, pt_err_array

    #else:
    pt_array = np.zeros((z_array.shape[0],2,2))

    for idx_f in range(len(z_array)):       
        
        realz = np.real(z_array[idx_f])
        imagz = np.imag(z_array[idx_f])

        detreal = np.linalg.det(realz)
        if detreal == 0 :
            raise MTex.MTpyError_Z('Warning - z-array no. {0} contains a singular matrix,'\
            ' thus it cannot be converted into a PT!'.format(idx_f))            

        pt_array[idx_f,0,0] =  realz[1,1] * imagz[0,0] - realz[0,1] * imagz[1,0] 
        pt_array[idx_f,0,1] =  realz[1,1] * imagz[0,1] - realz[0,1] * imagz[1,1] 
        pt_array[idx_f,1,0] =  realz[0,0] * imagz[1,0] - realz[1,0] * imagz[0,0] 
        pt_array[idx_f,1,1] =  realz[0,0] * imagz[1,1] - realz[1,0] * imagz[0,1] 

        pt_array /= detreal

        if z_err_array is None:
            return pt_array, pt_err_array

        pt_err_array = np.zeros_like(pt_array)
        pt_err_array[idx_f,0,0] = 1/detreal * (np.abs( -pt_array[idx_f,0,0] * realz[1,1] * z_err_array[0,0]) + \
                                        np.abs(  pt_array[idx_f,0,0] * realz[0,1] * z_err_array[1,0]) + \
                                        np.abs(  (imagz[0,0] - pt_array[idx_f,0,0] * realz[0,0] ) * z_err_array[1,1]) +\
                                        np.abs(  (-imagz[1,0]+ pt_array[idx_f,0,0] * realz[1,0] ) * z_err_array[0,1]) + \
                                        np.abs(  realz[1,1] * z_err_array[0,0]) + np.abs( realz[0,1] * z_err_array[1,0]) )

        pt_err_array[idx_f,0,1] = 1/detreal * (np.abs( -pt_array[idx_f,0,1] * realz[1,1] * z_err_array[0,0]) + \
                                        np.abs(  pt_array[idx_f,0,1] * realz[0,1] * z_err_array[1,0]) + \
                                        np.abs(  (imagz[0,1] - pt_array[idx_f,0,1] * realz[0,0] ) * z_err_array[1,1]) +\
                                        np.abs(  (-imagz[1,1]+ pt_array[idx_f,0,1] * realz[1,0] ) * z_err_array[0,1]) + \
                                        np.abs(  realz[1,1] * z_err_array[0,1]) + np.abs( realz[0,1] * z_err_array[1,1]) )

        pt_err_array[idx_f,1,0] = 1/detreal * (np.abs(  (imagz[1,0] - pt_array[idx_f,1,0] * realz[1,1] ) * z_err_array[0,0]) +\
                                        np.abs( pt_array[idx_f,1,0] * realz[1,0] * z_err_array[0,1]) + \
                                        np.abs(  (-imagz[0,0] + pt_array[idx_f,1,0] * realz[0,1] ) * z_err_array[1,0]) + \
                                        np.abs( -pt_array[idx_f,1,0] * realz[0,0] * z_err_array[1,1]) + \
                                        np.abs(  realz[0,0] * z_err_array[1,0]) + np.abs( -realz[1,0] * z_err_array[0,0]) )

        pt_err_array[idx_f,1,1] = 1/detreal * (np.abs(  (imagz[1,1] - pt_array[idx_f,1,1] * realz[1,1] ) * z_err_array[0,0]) +\
                                        np.abs( pt_array[idx_f,1,1] * realz[1,0] * z_err_array[0,1]) + \
                                        np.abs(  (-imagz[0,1] + pt_array[idx_f,1,1] * realz[0,1] ) * z_err_array[1,0]) + \
                                        np.abs( -pt_array[idx_f,1,1] * realz[0,0] * z_err_array[1,1]) + \
                                        np.abs(  realz[0,0] * z_err_array[1,1]) + np.abs( -realz[1,0] * z_err_array[0,1]) )

    return pt_array, pt_err_array