예제 #1
0
def test_warn_if_division_makes_too_small():
    "gravmag.tesseroid warn if not dividing further bc tesseroid got too small"
    # When tesseroids get below a threshold, they should not divide further and
    # compute as is instead. Otherwise results in ZeroDivisionError involving
    # some trigonometric functions.
    ds = 1e-6
    models = [
        [Tesseroid(-ds, ds, -ds, ds, 0, -1000, {'density': 100})],
        [Tesseroid(-1e-3, 1e-3, -1e-3, 1e-3, 0, -1e-2, {'density': 100})]]
    lat, lon = np.zeros((2, 1))
    h = np.array([0.1])
    warning_msg = (
        "Stopped dividing a tesseroid because it's dimensions would be below "
        + "the minimum numerical threshold (1e-6 degrees or 1e-3 m). "
        + "Will compute without division. Cannot guarantee the accuracy of "
        + "the solution.")
    for i, model in enumerate(models):
        with warnings.catch_warnings(record=True) as w:
            # Cause all warnings to always be triggered.
            warnings.simplefilter("always")
            tesseroid.gz(lon, lat, h, model)
            msg = ("Failed model {}. Got {} warnings.\n\n".format(i, len(w))
                   + "\n\n".join([str(j.message) for j in w]))
            assert len(w) >= 1, msg
            assert any(issubclass(j.category, RuntimeWarning) for j in w), \
                "No RuntimeWarning found. " + msg
            assert any(warning_msg in str(j.message) for j in w), \
                "Message mismatch. " + msg
예제 #2
0
def test_warn_if_too_small():
    "gravmag.tesseroid warns if ignoring tesseroid that is too small"
    ds = 1e-6 / 2
    models = [[
        Tesseroid(-ds, ds, -ds, ds, 0, -1000, {'density': density_fun})
    ], [
        Tesseroid(-1e-2, 1e-2, -1e-2, 1e-2, 0, -1e-4, {'density': density_fun})
    ]]
    lat, lon = np.zeros((2, 1))
    h = np.array([10])
    warning_msg = ("Encountered tesseroid with dimensions smaller than the " +
                   "numerical threshold (1e-6 degrees or 1e-3 m). " +
                   "Ignoring this tesseroid.")
    for i, model in enumerate(models):
        with warnings.catch_warnings(record=True) as w:
            # Cause all warnings to always be triggered.
            warnings.simplefilter("always")
            tesseroid.gz(lon, lat, h, model)
            msg = ("Failed model {}. Got {} warnings.\n\n".format(i, len(w)) +
                   "\n\n".join([str(j.message) for j in w]))
            assert len(w) >= 1, msg
            assert any(issubclass(j.category, RuntimeWarning) for j in w), \
                "No RuntimeWarning found. " + msg
            assert any(warning_msg in str(j.message) for j in w), \
                "Message mismatch. " + msg
예제 #3
0
def test_laplace_equation():
    "gravmag.tesseroid obeys Laplace equation"
    model = [
        Tesseroid(0, 1, 0, 1, 1000, -20000, {'density': density_fun}),
        Tesseroid(-1.5, 1.5, -1.5, -1, -1000, -20000,
                  {'density': density_fun_1}),
        Tesseroid(0.1, 0.6, -0.8, -0.3, 10000, -20000,
                  {'density': density_fun_2}),
    ]
    area = [-2, 2, -2, 2]
    shape = (51, 51)
    lon, lat, h = gridder.regular(area, shape, z=50000)
    gxx = tesseroid.gxx(lon, lat, h, model)
    gyy = tesseroid.gyy(lon, lat, h, model)
    gzz = tesseroid.gzz(lon, lat, h, model)
    trace = gxx + gyy + gzz
    assert_array_almost_equal(
        trace, np.zeros_like(lon), 9,
        'Failed whole model. Max diff %.15g' % (np.abs(trace).max()))
    for tess in model:
        gxx = tesseroid.gxx(lon, lat, h, [tess])
        gyy = tesseroid.gyy(lon, lat, h, [tess])
        gzz = tesseroid.gzz(lon, lat, h, [tess])
        trace = gxx + gyy + gzz
        assert_array_almost_equal(
            trace, np.zeros_like(lon), 9,
            'Failed tesseroid %s. Max diff %.15g' %
            (str(tess.get_bounds()), np.abs(trace).max()))
예제 #4
0
def test_detect_invalid_tesseroid_dimensions():
    "gravmag.tesseroid raises error when tesseroids with bad dimensions"
    props = dict(density=2000)
    model = [Tesseroid(0, -10, 4, 5, 1000, 0, props),
             Tesseroid(-10, 0, 5, 4, 1000, 0, props),
             Tesseroid(-10, 0, 5, 4, 0, 1000, props)]
    lon, lat, height = gridder.regular((-20, 20, -20, 20), (50, 50), z=250e3)
    for f in 'potential gx gy gz gxx gxy gxz gyy gyz gzz'.split():
        func = getattr(tesseroid, f)
        for t in model:
            raises(AssertionError, func, lon, lat, height, [t])
예제 #5
0
 def __init__(self, i, location, tess, props):
     Tesseroid.__init__(self,
                        tess.w,
                        tess.e,
                        tess.s,
                        tess.n,
                        tess.top,
                        tess.bottom,
                        props=props)
     self.i = i
     self.seed = i
     self.x, self.y, self.z = location
예제 #6
0
def test_overwrite_density():
    "gravmag.tesseroid uses given density instead of tesseroid property"
    model = [Tesseroid(0, 1, 0, 1, 1000, -20000, {'density': 2670})]
    density = -1000
    other = [Tesseroid(0, 1, 0, 1, 1000, -20000, {'density': density})]
    area = [-2, 2, -2, 2]
    shape = (51, 51)
    lon, lat, h = gridder.regular(area, shape, z=250000)
    funcs = ['potential', 'gx', 'gy', 'gz', 'gxx', 'gxy', 'gxz', 'gyy', 'gyz',
             'gzz']
    for f in funcs:
        correct = getattr(tesseroid, f)(lon, lat, h, other)
        effect = getattr(tesseroid, f)(lon, lat, h, model, dens=density)
        assert_array_almost_equal(correct, effect, 9, 'Failed %s' % (f))
예제 #7
0
def test_ignore_zero_volume():
    "gravmag.tesseroid ignores tesseroids with 0 volume"
    props = dict(density=2000)
    model = [Tesseroid(-10, 0, 4, 5, 1000.1, 1000.1, props),
             Tesseroid(-10, 0, 4, 5, 1000.001, 1000, props),
             Tesseroid(-10, 0, 3.999999999, 4, 1000, 0, props),
             Tesseroid(-10, -9.9999999999, 4, 5, 1000, 0, props),
             Tesseroid(5, 10, -10, -5, 2000.5, 0, props)]
    lon, lat, height = gridder.regular((-20, 20, -20, 20), (50, 50), z=250e3)
    for f in 'potential gx gy gz gxx gxy gxz gyy gyz gzz'.split():
        with warnings.catch_warnings(record=True) as w:
            func = getattr(tesseroid, f)
            f1 = func(lon, lat, height, model)
            f2 = func(lon, lat, height, [model[-1]])
        assert_allclose(f1, f2, err_msg="Mismatch for {}".format(f))
예제 #8
0
def test_pool_as_argument():
    "gravmag.tesseroid takes an open Pool as argument and uses it"

    class MockPool(object):
        "Record if the map method of pool was used."

        def __init__(self, pool):
            self.pool = pool
            self.used = False

        def map(self, *args):
            res = self.pool.map(*args)
            self.used = True
            return res

    njobs = 2
    pool = MockPool(multiprocessing.Pool(njobs))
    model = [Tesseroid(0, 1, 0, 1, 2000, 0, {'density': density_fun})]
    lon, lat, height = gridder.regular((-1, 2, -1, 2), (20, 20), z=250e3)
    for f in 'potential gx gy gz gxx gxy gxz gyy gyz gzz'.split():
        func = getattr(tesseroid, f)
        f1 = func(lon, lat, height, model)
        f2 = func(lon, lat, height, model, njobs=njobs, pool=pool)
        assert_allclose(f1, f2, err_msg="Mismatch for {}".format(f))
        assert pool.used, "The given pool was not used in {}".format(f)
        with raises(AssertionError):
            func(lon, lat, height, model, njobs=1, pool=pool)
예제 #9
0
def crust2_to_tesseroids(fname):
    """
    Convert the CRUST2.0 model to tesseroids.

    Opens the .tar.gz archive and converts the model to
    :class:`fatiando.mesher.Tesseroid`.
    Each tesseroid will have its ``props`` set to the apropriate Vp, Vs and
    density.

    The CRUST2.0 model includes 7 layers: ice, water, soft sediments, hard
    sediments, upper crust, middle curst and lower crust. It also includes the
    mantle below the Moho. The mantle portion is not included in this
    conversion because there is no way to place a bottom on it.

    Parameters:

    * fname : str
        Name of the model .tar.gz archive (see
        :func:`~fatiando.io.fetch_crust2`)

    Returns:

    * model : list of :class:`fatiando.mesher.Tesseroid`
        The converted model

    """
    # Needs to be inside the function to avoid circular imports
    from fatiando.mesher import Tesseroid
    archive = tarfile.open(fname, 'r:gz')
    # First get the topography and bathymetry information
    topogrd = _crust2_get_topo(archive)
    # Now make a dict with the codec for each type code
    codec = _crust2_get_codec(archive)
    # Get the type codes with the actual model
    types = _crust2_get_types(archive)
    # Convert to tesseroids
    size = 2
    lons = numpy.arange(-180, 180, size)
    lats = numpy.arange(90, -90, -size)  # This is how lats are in the file
    model = []
    for i in xrange(len(lats)):
        for j in xrange(len(lons)):
            t = types[i][j]
            top = topogrd[i][j]
            for layer in xrange(7):
                if codec[t]['thickness'][layer] == 0:
                    continue
                w, e, s, n = lons[j], lons[j] + size, lats[i] - size, lats[i]
                bottom = top - codec[t]['thickness'][layer]
                props = {
                    'density': codec[t]['density'][layer],
                    'vp': codec[t]['vp'][layer],
                    'vs': codec[t]['vs'][layer]
                }
                model.append(Tesseroid(w, e, s, n, top, bottom, props))
                top = bottom
    return model
예제 #10
0
def _split(tesseroid):
    dlon = 0.5 * (tesseroid.e - tesseroid.w)
    dlat = 0.5 * (tesseroid.n - tesseroid.s)
    dh = 0.5 * (tesseroid.top - tesseroid.bottom)
    wests = [tesseroid.w, tesseroid.w + dlon]
    souths = [tesseroid.s, tesseroid.s + dlat]
    bottoms = [tesseroid.bottom, tesseroid.bottom + dh]
    split = [
        Tesseroid(i, i + dlon, j, j + dlat, k + dh, k, props=tesseroid.props)
        for i in wests for j in souths for k in bottoms
    ]
    return split
예제 #11
0
def test_skip_none_and_missing_properties():
    "gravmag.tesseroid ignores Nones and tesseroids without density prop"
    model = [
        Tesseroid(0, 1, 0, 1, 1000, -20000, {'density': density_fun}), None,
        Tesseroid(-1.5, -0.5, -1.5, -1, -1000, -20000),
        Tesseroid(0.1, 0.6, -0.8, -0.3, 10000, -20000,
                  {'magnetization': [1, 2, 3]}), None, None,
        Tesseroid(-1.5, -0.5, -1.5, -1, 1000, -20000, {
            'density': density_fun,
            'magnetization': [1, 2, 3]
        }), None
    ]
    puremodel = [
        Tesseroid(0, 1, 0, 1, 1000, -20000, {'density': density_fun}),
        Tesseroid(-1.5, -0.5, -1.5, -1, 1000, -20000, {'density': density_fun})
    ]
    area = [-2, 2, -2, 2]
    shape = (51, 51)
    lon, lat, h = gridder.regular(area, shape, z=150000)
    funcs = [
        'potential', 'gx', 'gy', 'gz', 'gxx', 'gxy', 'gxz', 'gyy', 'gyz', 'gzz'
    ]
    for f in funcs:
        pure = getattr(tesseroid, f)(lon, lat, h, puremodel)
        dirty = getattr(tesseroid, f)(lon, lat, h, model)
        assert_array_almost_equal(pure, dirty, 9, 'Failed %s' % (f))
예제 #12
0
def test_fails_if_shape_mismatch():
    'gravmag.tesseroid fails if given computation points with different shapes'
    model = [Tesseroid(0, 1, 0, 1, 1000, -20000, {'density': 2670})]
    area = [-2, 2, -2, 2]
    shape = (51, 51)
    lon, lat, h = gridder.regular(area, shape, z=100000)

    for f in 'potential gx gy gz gxx gxy gxz gyy gyz gzz'.split():
        func = getattr(tesseroid, f)
        raises(AssertionError, func, lon[:-2], lat, h, model)
        raises(AssertionError, func, lon, lat[:-2], h, model)
        raises(AssertionError, func, lon, lat, h[:-2], model)
        raises(AssertionError, func, lon[:-5], lat, h[:-2], model)
예제 #13
0
 def __getitem__(self, index):
     nlat, nlon = self.shape
     dlat, dlon = self.spacing
     i = index//nlon
     j = index - i*nlon
     w = self.lons[j] - dlon/2.
     e = w + dlon
     s = self.lats[i] - dlon/2.
     n = s + dlat
     top = self.top[index]
     bottom = self.bottom[index]
     props = {}
     for p in self.props:
         props[p] = self.props[p][index]
     cell = Tesseroid(w, e, s, n, top, bottom, props)
     return cell
 def tesseroids(self):
     """
     Get a tesseroid representation of this layer.
     """
     assert self.bottom is not None, "Bottomless layer cannot be converted to tesseroids."
     ds = (self.lon[0, 1] - self.lon[0, 0]) / 2
     arrays = [
         self.lon, self.lat, self.top, self.bottom, self.vp, self.vs,
         self.density
     ]
     args = zip(*[i.ravel() for i in arrays])
     gen = (Tesseroid(lon - ds, lon + ds, lat - ds, lat + ds, top, bottom,
                      dict(vp=vp, vs=vs, density=density))
            for lon, lat, top, bottom, vp, vs, density in args
            if abs(top - bottom) > 10)
     return gen
def setup():
    "Make a spherical shell model with tesseroids"
    global shellmodel, heights, density, props, top, bottom
    tlons = np.linspace(-90, 90, 50, endpoint=False)
    tlats = np.linspace(-90, 90, 50, endpoint=False)
    wsize = tlons[1] - tlons[0]
    ssize = tlats[1] - tlats[0]
    density = 1000.
    props = {'density': density}
    top = 0
    bottom = -50000
    shellmodel = [
        Tesseroid(w, w + wsize, s, s + ssize, top, bottom, props)
        for w in tlons for s in tlats
    ]
    heights = np.linspace(250000, 1000000, 10)
예제 #16
0
def test_stack_overflow():
    "gravmag.tesseroid raises exceptions on stack overflow"
    model = [Tesseroid(0, 1, 0, 1, 0, -20e4, {'density': 2600})]
    area = [0, 1, 0, 1]
    shape = [20, 20]
    lon, lat, h = gridder.regular(area, shape, z=1000)
    fields = 'potential gx gy gz gxx gxy gxz gyy gyz gzz'.split()
    backup = tesseroid.STACK_SIZE
    tesseroid.STACK_SIZE = 5
    for f in fields:
        raises(OverflowError, getattr(tesseroid, f), lon, lat, h, model)
    # Check if overflows on normal queue size when trying to calculated on top
    # of the tesseroid
    tesseroid.STACK_SIZE = 20
    lon, lat, h = np.array([0.5]), np.array([0.5]), np.array([0])
    for f in fields:
        raises(OverflowError, getattr(tesseroid, f), lon, lat, h, model)
    # Restore the module default queue size
    tesseroid.STACK_SIZE = backup
from fatiando.vis import mpl, myv

# Make a "crust" model with some thinker crust and variable density
marea = (-70, 70, -70, 70)
mshape = (200, 200)
mlons, mlats = gridder.regular(marea, mshape)
dlon, dlat = gridder.spacing(marea, mshape)
depths = (30000 + 70000 * utils.gaussian2d(mlons, mlats, 10, 10, -20, -20) +
          20000 * utils.gaussian2d(mlons, mlats, 5, 5, 20, 20))
densities = (2700 + 500 * utils.gaussian2d(mlons, mlats, 40, 40, -20, -20) +
             -300 * utils.gaussian2d(mlons, mlats, 20, 20, 20, 20))
model = [
    Tesseroid(lon - 0.5 * dlon,
              lon + 0.5 * dlon,
              lat - 0.5 * dlat,
              lat + 0.5 * dlat,
              0,
              -depth,
              props={'density': density})
    for lon, lat, depth, density in zip(mlons, mlats, depths, densities)
]

# Plot the tesseroid model
myv.figure(zdown=False)
myv.tesseroids(model, 'density')
myv.continents()
myv.earth(opacity=0.7)
myv.show()

# Make the computation grid
area = (-50, 50, -50, 50)
예제 #18
0
import matplotlib.pyplot as plt
# This is our custom tesseroid code
from tesseroid_density import tesseroid


# Configure comparison
# --------------------
nruns = 1000
fields = "potential gz".split()


# Define Tesseroid
# ----------------
w, e, s, n = -10, 10, -10, 10
top, bottom = 0, -1e3
model = [Tesseroid(w, e, s, n, top, bottom)]


# Define computation points
# -------------------------
heights = np.array([1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6])
computation_points = [[np.array([0.]), np.array([0.]), np.array([height])]
                      for height in heights]


# Create results dir if it does not exist
# -------------------------
script_path = os.path.dirname(os.path.abspath(__file__))
result_dir = os.path.join(script_path, 'results/computation_time')
if not os.path.isdir(result_dir):
    os.makedirs(result_dir)
예제 #19
0
"""
Vis: Set the colors in figures, prisms, polygonal prisms and tesseroids.
"""
from fatiando.mesher import Prism, PolygonalPrism, Tesseroid
from fatiando.vis import myv

prism = Prism(1, 2, 1, 2, 0, 1, {'density': 1})
polyprism = PolygonalPrism([[3, 1], [4, 2], [5, 1]], -1, 2, {'density': 2})
tesseroid = Tesseroid(10, 20, 50, 60, 10**6, 0)

red, green, blue = (1, 0, 0), (0, 1, 0), (0, 0, 1)
white, black = (1, 1, 1), (0, 0, 0),

myv.figure()
# Make the prism red with blue edges, despite its density
myv.prisms([prism], 'density', color=red, edgecolor=blue)
# and the polyprism green with blue edges
myv.title('Body + edge colors')

myv.figure()
# For wireframes, color is usually set by the density.
# Overwrite this by setting *color*
# *edgecolor* is ignored
myv.polyprisms([polyprism],
               'density',
               style='wireframe',
               color=green,
               edgecolor=red,
               linewidth=2)
myv.title('Wireframe colors')
예제 #20
0
"""
GravMag: Forward modeling of the gravitational potential and its derivatives
using tesseroids
"""
import time
from fatiando import gravmag, gridder, utils
from fatiando.mesher import Tesseroid
from fatiando.vis import mpl, myv

model = [
    Tesseroid(-60, -55, -30, -27, 0, -500000, props={'density': 200}),
    Tesseroid(-66, -62, -18, -12, 0, -300000, props={'density': -500})
]
# Show the model before calculating
scene = myv.figure(zdown=False)
myv.tesseroids(model, 'density')
myv.continents(linewidth=2)
myv.earth(opacity=0.8)
myv.meridians(range(0, 360, 45), opacity=0.2)
myv.parallels(range(-90, 90, 45), opacity=0.2)
scene.scene.camera.position = [
    23175275.131412581, -16937347.013663091, -4924328.2822419703
]
scene.scene.camera.focal_point = [0.0, 0.0, 0.0]
scene.scene.camera.view_angle = 30.0
scene.scene.camera.view_up = [
    0.083030001958377356, -0.17178720527713925, 0.98162883763562181
]
scene.scene.camera.clipping_range = [9229054.5133903362, 54238225.321054712]
scene.scene.camera.compute_view_plane_normal()
scene.scene.render()
 def __init__(self, i, location, tess, props):
     Tesseroid.__init__(self, tess.w, tess.e, tess.s, tess.n, tess.top,
         tess.bottom, props=props)
     self.i = i
     self.seed = i
     self.x, self.y, self.z = location