The fatiando package has been deprecated. Please check out the new tools in the Fatiando a Terra website: www.fatiando.org

Source code for fatiando.gravmag.polyprism

r"""
Calculate the potential fields of the 3D prism with polygonal crossection using
the formula of Plouff (1976).

**Gravity**

First and second derivatives of the gravitational potential:

* :func:`~fatiando.gravmag.polyprism.gz`
* :func:`~fatiando.gravmag.polyprism.gxx`
* :func:`~fatiando.gravmag.polyprism.gxy`
* :func:`~fatiando.gravmag.polyprism.gxz`
* :func:`~fatiando.gravmag.polyprism.gyy`
* :func:`~fatiando.gravmag.polyprism.gyz`
* :func:`~fatiando.gravmag.polyprism.gzz`

**Magnetic**

There are functions to calculate the total-field anomaly and the 3 components
of magnetic induction:

* :func:`~fatiando.gravmag.polyprism.tf`
* :func:`~fatiando.gravmag.polyprism.bx`
* :func:`~fatiando.gravmag.polyprism.by`
* :func:`~fatiando.gravmag.polyprism.bz`

**Auxiliary Functions**

Calculates the second derivatives of the function

.. math::

    \phi(x,y,z) = \int\int\int \frac{1}{r}
                  \mathrm{d}\nu \mathrm{d}\eta \mathrm{d}\zeta

with respect to the variables :math:`x`, :math:`y`, and :math:`z`.
In this equation,

.. math::

    r = \sqrt{(x - \nu)^2 + (y - \eta)^2 + (z - \zeta)^2}

and :math:`\nu`, :math:`\eta`, :math:`\zeta` are the Cartesian
coordinates of an element inside the volume of a 3D prism with
polygonal crossection. These second derivatives are used to calculate
the total field anomaly and the gravity gradient tensor
components produced by a 3D prism with polygonal crossection.

* :func:`~fatiando.gravmag.polyprism.kernelxx`
* :func:`~fatiando.gravmag.polyprism.kernelxy`
* :func:`~fatiando.gravmag.polyprism.kernelxz`
* :func:`~fatiando.gravmag.polyprism.kernelyy`
* :func:`~fatiando.gravmag.polyprism.kernelyz`
* :func:`~fatiando.gravmag.polyprism.kernelzz`

**References**

Plouff, D. , 1976, Gravity and magnetic fields of polygonal prisms and
applications to magnetic terrain corrections, Geophysics, 41(4), 727-741.

----

"""
from __future__ import division

import numpy
from numpy import arctan2, log, sqrt

from .. import utils
from ..constants import SI2MGAL, SI2EOTVOS, G, CM, T2NT
try:
    from . import _polyprism
except ImportError:
    _polyprism = None


[docs]def tf(xp, yp, zp, prisms, inc, dec, pmag=None): r""" Calculate the total-field anomaly of polygonal prisms. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: Input units are SI. Output is in nT Parameters: * xp, yp, zp : arrays Arrays with the x, y, and z coordinates of the computation points. * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the total field anomaly. Prisms without the physical property ``'magnetization'`` will be ignored. * inc : float The inclination of the regional field (in degrees) * dec : float The declination of the regional field (in degrees) * pmag : [mx, my, mz] or None A magnetization vector. If not None, will use this value instead of the ``'magnetization'`` property of the prisms. Use this, e.g., for sensitivity matrix building. Returns: * res : array The field calculated on xp, yp, zp """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") # Calculate the 3 components of the unit vector in the direction of the # regional field fx, fy, fz = utils.dircos(inc, dec) if pmag is not None: if isinstance(pmag, float) or isinstance(pmag, int): pmx, pmy, pmz = pmag * fx, pmag * fy, pmag * fz else: pmx, pmy, pmz = pmag res = numpy.zeros(len(xp), dtype=numpy.float) for prism in prisms: if prism is None or ('magnetization' not in prism.props and pmag is None): continue if pmag is None: mag = prism.props['magnetization'] if isinstance(mag, float) or isinstance(mag, int): mx, my, mz = mag * fx, mag * fy, mag * fz else: mx, my, mz = mag else: mx, my, mz = pmx, pmy, pmz x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 _polyprism.tf(xp, yp, zp, x, y, z1, z2, mx, my, mz, fx, fy, fz, res) res *= CM * T2NT return res
[docs]def bx(xp, yp, zp, prisms): """ Calculates the x component of the magnetic induction produced by 3D prisms with polygonal crosssection. .. note:: Input units are SI. Output is in nT Parameters: * xp, yp, zp : arrays The x, y, and z coordinates where the anomaly will be calculated * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the total field anomaly. Prisms without the physical property ``'magnetization'`` will be ignored. The ``'magnetization'`` must be a vector. Returns: * bx: array The x component of the magnetic induction """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) for prism in prisms: if prism is None or ('magnetization' not in prism.props): continue # Get the magnetization vector components mx, my, mz = prism.props['magnetization'] x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 _polyprism.bx(xp, yp, zp, x, y, z1, z2, mx, my, mz, res) res *= CM * T2NT return res
[docs]def by(xp, yp, zp, prisms): """ Calculates the y component of the magnetic induction produced by 3D prisms with polygonal crosssection. .. note:: Input units are SI. Output is in nT Parameters: * xp, yp, zp : arrays The x, y, and z coordinates where the anomaly will be calculated * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the total field anomaly. Prisms without the physical property ``'magnetization'`` will be ignored. The ``'magnetization'`` must be a vector. Returns: * by: array The y component of the magnetic induction """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) for prism in prisms: if prism is None or ('magnetization' not in prism.props): continue # Get the magnetization vector components mx, my, mz = prism.props['magnetization'] x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 _polyprism.by(xp, yp, zp, x, y, z1, z2, mx, my, mz, res) res *= CM * T2NT return res
[docs]def bz(xp, yp, zp, prisms): """ Calculates the z component of the magnetic induction produced by 3D prisms with polygonal crosssection. .. note:: Input units are SI. Output is in nT Parameters: * xp, yp, zp : arrays The x, y, and z coordinates where the anomaly will be calculated * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the total field anomaly. Prisms without the physical property ``'magnetization'`` will be ignored. The ``'magnetization'`` must be a vector. Returns: * bz: array The z component of the magnetic induction """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) for prism in prisms: if prism is None or ('magnetization' not in prism.props): continue # Get the magnetization vector components mx, my, mz = prism.props['magnetization'] x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 _polyprism.bz(xp, yp, zp, x, y, z1, z2, mx, my, mz, res) res *= CM * T2NT return res
[docs]def gz(xp, yp, zp, prisms): r""" Calculates the :math:`g_{z}` gravity acceleration component. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input values in SI units and output in mGal! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the field. Prisms must have the physical property ``'density'`` will be ignored. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") dummy = 10 ** (-10) size = len(xp) res = numpy.zeros(size, dtype=numpy.float) for prism in prisms: if prism is None or 'density' not in prism.props: continue x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 density = prism.props['density'] _polyprism.gz(xp, yp, zp, x, y, z1, z2, density, res) res *= G * SI2MGAL return res
[docs]def gxx(xp, yp, zp, prisms): r""" Calculates the :math:`g_{xx}` gravity gradient tensor component. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input values in SI units and output in Eotvos! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the field. Prisms must have the physical property ``'density'`` will be ignored. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) for prism in prisms: if prism is None or 'density' not in prism.props: continue density = prism.props['density'] x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 density = prism.props['density'] _polyprism.gxx(xp, yp, zp, x, y, z1, z2, density, res) res *= G * SI2EOTVOS return res
[docs]def gxy(xp, yp, zp, prisms): r""" Calculates the :math:`g_{xy}` gravity gradient tensor component. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input values in SI units and output in Eotvos! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the field. Prisms must have the physical property ``'density'`` will be ignored. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) for prism in prisms: if prism is None or 'density' not in prism.props: continue density = prism.props['density'] x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 density = prism.props['density'] _polyprism.gxy(xp, yp, zp, x, y, z1, z2, density, res) res *= G * SI2EOTVOS return res
[docs]def gxz(xp, yp, zp, prisms): r""" Calculates the :math:`g_{xz}` gravity gradient tensor component. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input values in SI units and output in Eotvos! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the field. Prisms must have the physical property ``'density'`` will be ignored. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) for prism in prisms: if prism is None or 'density' not in prism.props: continue density = prism.props['density'] x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 density = prism.props['density'] _polyprism.gxz(xp, yp, zp, x, y, z1, z2, density, res) res *= G * SI2EOTVOS return res
[docs]def gyy(xp, yp, zp, prisms): r""" Calculates the :math:`g_{yy}` gravity gradient tensor component. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input values in SI units and output in Eotvos! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the field. Prisms must have the physical property ``'density'`` will be ignored. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) for prism in prisms: if prism is None or 'density' not in prism.props: continue density = prism.props['density'] x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 density = prism.props['density'] _polyprism.gyy(xp, yp, zp, x, y, z1, z2, density, res) res *= G * SI2EOTVOS return res
[docs]def gyz(xp, yp, zp, prisms): r""" Calculates the :math:`g_{yz}` gravity gradient tensor component. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input values in SI units and output in Eotvos! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the field. Prisms must have the physical property ``'density'`` will be ignored. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) for prism in prisms: if prism is None or 'density' not in prism.props: continue density = prism.props['density'] x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 density = prism.props['density'] _polyprism.gyz(xp, yp, zp, x, y, z1, z2, density, res) res *= G * SI2EOTVOS return res
[docs]def gzz(xp, yp, zp, prisms): r""" Calculates the :math:`g_{zz}` gravity gradient tensor component. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input values in SI units and output in Eotvos! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : list of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the field. Prisms must have the physical property ``'density'`` will be ignored. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) for prism in prisms: if prism is None or 'density' not in prism.props: continue density = prism.props['density'] x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 density = prism.props['density'] _polyprism.gzz(xp, yp, zp, x, y, z1, z2, density, res) res *= G * SI2EOTVOS return res
[docs]def kernelxx(xp, yp, zp, prism): r""" Calculates the function .. math:: \frac{\partial^2 \phi(x,y,z)}{\partial x^2}, where .. math:: \phi(x,y,z) = \int \int \int \frac{1}{r} \mathrm{d}\nu \mathrm{d}\eta \mathrm{d}\zeta and .. math:: r = \sqrt{(x - \nu)^2 + (y - \eta)^2 + (z - \zeta)^2}. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input and output values in SI! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : object of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the function. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 _polyprism.gxx(xp, yp, zp, x, y, z1, z2, 1, res) return res
[docs]def kernelxy(xp, yp, zp, prism): r""" Calculates the function .. math:: \frac{\partial^2 \phi(x,y,z)}{\partial x \partial y}, where .. math:: \phi(x,y,z) = \int \int \int \frac{1}{r} \mathrm{d}\nu \mathrm{d}\eta \mathrm{d}\zeta and .. math:: r = \sqrt{(x - \nu)^2 + (y - \eta)^2 + (z - \zeta)^2}. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input and output values in SI! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : object of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the function. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 _polyprism.gxy(xp, yp, zp, x, y, z1, z2, 1, res) return res
[docs]def kernelxz(xp, yp, zp, prism): r""" Calculates the function .. math:: \frac{\partial^2 \phi(x,y,z)}{\partial x \partial z}, where .. math:: \phi(x,y,z) = \int \int \int \frac{1}{r} \mathrm{d}\nu \mathrm{d}\eta \mathrm{d}\zeta and .. math:: r = \sqrt{(x - \nu)^2 + (y - \eta)^2 + (z - \zeta)^2}. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input and output values in SI! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : object of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the function. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 _polyprism.gxz(xp, yp, zp, x, y, z1, z2, 1, res) return res
[docs]def kernelyy(xp, yp, zp, prism): r""" Calculates the function .. math:: \frac{\partial^2 \phi(x,y,z)}{\partial y^2}, where .. math:: \phi(x,y,z) = \int \int \int \frac{1}{r} \mathrm{d}\nu \mathrm{d}\eta \mathrm{d}\zeta and .. math:: r = \sqrt{(x - \nu)^2 + (y - \eta)^2 + (z - \zeta)^2}. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input and output values in SI! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : object of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the function. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 _polyprism.gyy(xp, yp, zp, x, y, z1, z2, 1, res) return res
[docs]def kernelyz(xp, yp, zp, prism): r""" Calculates the function .. math:: \frac{\partial^2 \phi(x,y,z)}{\partial y \partial z}, where .. math:: \phi(x,y,z) = \int \int \int \frac{1}{r} \mathrm{d}\nu \mathrm{d}\eta \mathrm{d}\zeta and .. math:: r = \sqrt{(x - \nu)^2 + (y - \eta)^2 + (z - \zeta)^2}. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input and output values in SI! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : object of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the function. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 _polyprism.gyz(xp, yp, zp, x, y, z1, z2, 1, res) return res
[docs]def kernelzz(xp, yp, zp, prism): r""" Calculates the function .. math:: \frac{\partial^2 \phi(x,y,z)}{\partial z^2}, where .. math:: \phi(x,y,z) = \int \int \int \frac{1}{r} \mathrm{d}\nu \mathrm{d}\eta \mathrm{d}\zeta and .. math:: r = \sqrt{(x - \nu)^2 + (y - \eta)^2 + (z - \zeta)^2}. .. note:: The coordinate system of the input parameters is to be x -> North, y -> East and z -> Down. .. note:: All input and output values in SI! Parameters: * xp, yp, zp : arrays The x, y, and z coordinates of the computation points. * prisms : object of :class:`fatiando.mesher.PolygonalPrism` The model used to calculate the function. Returns: * res : array The effect calculated on the computation points. """ if xp.shape != yp.shape != zp.shape: raise ValueError("Input arrays xp, yp, and zp must have same shape!") res = numpy.zeros(len(xp), dtype=numpy.float) x, y = prism.x, prism.y z1, z2 = prism.z1, prism.z2 _polyprism.gzz(xp, yp, zp, x, y, z1, z2, 1, res) return res