def test_eqlayer_polereduce(): "EQLTotalField can reduce data to the pole" # Use remanent magnetization sinc, sdec = -70, 30 model = [Prism(-100, 100, -500, 500, 0, 100, {'magnetization': utils.ang2vec(5, sinc, sdec)})] inc, dec = -60, -15 shape = (50, 50) area = [-2000, 2000, -2000, 2000] x, y, z = gridder.regular(area, shape, z=-100) data = prism.tf(x, y, z, model, inc, dec) true = prism.tf(x, y, z, model, -90, 0, pmag=utils.ang2vec(5, -90, 0)) layer = PointGrid(area, 200, shape) eql = (EQLTotalField(x, y, z, data, inc, dec, layer, sinc, sdec) + 1e-24*Damping(layer.size)) eql.fit() assert_allclose(eql[0].predicted(), data, rtol=0.01) layer.addprop('magnetization', utils.ang2vec(eql.estimate_, inc=-90, dec=0)) calc = sphere.tf(x, y, z, layer, inc=-90, dec=0) assert_allclose(calc, true, atol=10, rtol=0.05)
def test_ignore_none_and_missing_properties(): 'gravmag.prism ignores None and prisms without the required property' inc, dec = 50, -30 model = [None, Prism(-6000, -2000, 2000, 4000, 0, 3000, {'density': 1000, 'magnetization': utils.ang2vec(10, inc, dec)}), Prism(2000, 6000, 2000, 4000, 0, 1000, {'magnetization': utils.ang2vec(15, inc, dec)}), None, Prism(-6000, -2000, -4000, -2000, 500, 2000, {'density': -1000})] area = [-10000, 10000, -5000, 5000] x, y, z = gridder.regular(area, (101, 51), z=-1) for mod in [prism, _prism_numpy]: # Test gravity functions funcs = ['potential', 'gx', 'gy', 'gz', 'gxx', 'gxy', 'gxz', 'gyy', 'gyz', 'gzz'] for f in funcs: combined = getattr(mod, f)(x, y, z, model) separate = getattr(mod, f)(x, y, z, [model[1], model[4]]) precision = 10 assert_almost(separate, combined, precision, 'Field = %s' % (f)) # Test magnetic functions funcs = ['tf', 'bx', 'by', 'bz'] for f in funcs: mag_only = [model[1], model[2]] if f == 'tf': combined = getattr(mod, f)(x, y, z, model, inc, dec) separate = getattr(mod, f)(x, y, z, mag_only, inc, dec) else: combined = getattr(mod, f)(x, y, z, model) separate = getattr(mod, f)(x, y, z, mag_only) precision = 10 assert_almost(separate, combined, precision, 'Field = %s' % (f))
def test_pel_polereduce(): "PELTotalField can reduce data to the pole" # Use remanent magnetization sinc, sdec = -70, 30 model = [Prism(-100, 100, -500, 500, 0, 100, {'magnetization': utils.ang2vec(5, sinc, sdec)})] inc, dec = -60, -15 shape = (40, 40) area = [-2000, 2000, -2000, 2000] x, y, z = gridder.regular(area, shape, z=-100) data = prism.tf(x, y, z, model, inc, dec) true = prism.tf(x, y, z, model, -90, 0, pmag=utils.ang2vec(5, -90, 0)) layer = PointGrid(area, 100, shape) windows = (20, 20) degree = 3 pel = PELTotalField(x, y, z, data, inc, dec, layer, windows, degree, sinc, sdec) eql = pel + 1e-25*PELSmoothness(layer, windows, degree) eql.fit() assert_array_almost_equal(eql[0].predicted(), data, decimal=1) layer.addprop('magnetization', utils.ang2vec(eql.estimate_, inc=-90, dec=0)) calc = sphere.tf(x, y, z, layer, inc=-90, dec=0) assert_allclose(calc, true, atol=10, rtol=0.05)
def test_upcontinue(): "gravmag.transform upward continuation matches analytical solution" model = [Prism(-1000, 1000, -500, 500, 0, 1000, {'density': 1000, 'magnetization': utils.ang2vec(5, 20, -30)})] shape = (100, 100) inc, dec = -10, 15 x, y, z = gridder.regular([-5000, 5000, -5000, 5000], shape, z=-500) dz = 10 fields = 'potential gx gy gz gxx gxy gxz gyy gyz gzz'.split() accuracy = [0.002, 0.2, 0.2, 0.3, 2, 2, 4, 4, 4, 6] for f, atol in zip(fields, accuracy): func = getattr(prism, f) data = func(x, y, z, model) analytical = func(x, y, z + dz, model) up = transform.upcontinue(x, y, data, shape, dz) diff = np.abs(up - analytical) check = diff <= atol assert np.all(check), \ 'Failed for {} (mismatch {:.2f}%)'.format( f, 100*(check.size - check.sum())/check.size) data = prism.tf(x, y, z, model, inc, dec) analytical = prism.tf(x, y, z + dz, model, inc, dec) up = transform.upcontinue(x, y, data, shape, dz) diff = np.abs(up - analytical) check = diff <= 15 assert np.all(check), \ 'Failed for tf (mismatch {:.2f}%)'.format( 100*(check.size - check.sum())/check.size)
def test_tesseroid_vs_spherical_shell(): "gravmag.tesseroid equal analytical solution of spherical shell to 0.1%" density = 1000. top = 1000 bottom = 0 model = TesseroidMesh((0, 360, -90, 90, top, bottom), (1, 6, 12)) model.addprop('density', density*np.ones(model.size)) h = 10000 lon, lat, height = gridder.regular((0, model.dims[0], 0, model.dims[1]), (10, 10), z=h) funcs = ['potential', 'gx', 'gy', 'gz', 'gxx', 'gxy', 'gxz', 'gyy', 'gyz', 'gzz'] shellvalues = calc_shell_effect(h, top, bottom, density) for f in funcs: shell = shellvalues[f] tess = getattr(tesseroid, f)(lon, lat, height, model) diff = np.abs(shell - tess) # gz gy and the off-diagonal gradients should be zero so I can't # calculate a relative error (in %). # To do that, I'll use the gz and gzz shell values to calculate the # percentage. if f in 'gx gy'.split(): shell = shellvalues['gz'] elif f in 'gxy gxz gyz'.split(): shell = shellvalues['gzz'] diff = 100*diff/np.abs(shell) assert diff.max() < 0.1, "diff > 0.1% for {}: {}".format( f, diff.max())
def test_fails_if_bad_pad_operation(): 'gridder.pad_array fails if given a bad padding array operation option' p = 'foo' shape = (100, 100) x, y, z = gridder.regular((-1000., 1000., -1000., 1000.), shape, z=-150) g = z.reshape(shape) assert_raises(ValueError, gridder.pad_array, g, padtype=p)
def test_radial_average_spectrum_distances(): shape = (201, 201) area = (-100, 100, -100, 100) x, y = gridder.regular(area, shape) x, y = x.reshape(shape), y.reshape(shape) x, y = np.fft.ifftshift(x), np.fft.ifftshift(y) distances = np.sqrt(x**2 + y**2) k, radial_distances = transform.radial_average_spectrum(x, y, distances) npt.assert_allclose(k[2:], radial_distances[2:], rtol=0.1) # doesn't fail
def setup(): global model, xp, yp, zp, inc, dec inc, dec = -30, 50 reg_field = np.array(utils.dircos(inc, dec)) model = [ Sphere(500, 0, 1000, 1000, {'density': -1., 'magnetization': utils.ang2vec(-2, inc, dec)}), Sphere(-1000, 0, 700, 700, {'density': 2., 'magnetization': utils.ang2vec(5, 25, -10)})] xp, yp, zp = gridder.regular([-2000, 2000, -2000, 2000], (50, 50), z=-1)
def test_upcontinue_warning(): "gravmag.transform upward continuation raises warning if height <= 0" model = [Prism(-1000, 1000, -500, 500, 0, 1000, {'density': 1000})] shape = (100, 100) x, y, z = gridder.regular([-5000, 5000, -5000, 5000], shape, z=-500) data = prism.gz(x, y, z, model) with pytest.warns(UserWarning): up = transform.upcontinue(x, y, data, shape, height=0) with pytest.warns(UserWarning): up = transform.upcontinue(x, y, data, shape, height=-100)
def test_numba_vs_python(): "gravmag.tesseroid numba and pure python implementations give same result" model = TesseroidMesh((0, 1, 0, 2, 1000, 0), (2, 2, 1)) model.addprop('density', -200*np.ones(model.size)) lon, lat, height = gridder.regular((0, 1, 0, 2), (20, 20), z=250e3) for f in 'potential gx gy gz gxx gxy gxz gyy gyz gzz'.split(): func = getattr(tesseroid, f) py = func(lon, lat, height, model, engine='numpy') nb = func(lon, lat, height, model, engine='numba') assert_allclose(nb, py, err_msg="Mismatch for {}".format(f))
def test_fails_if_npd_lessthan_arraydim(): 'gridder.pad_array raises error if given npad is less than array length' shape = (101, 172) x, y, z = gridder.regular((-5000., 5000., -5000., 5000.), shape, z=-150) g = z.reshape(shape) npdt = (128, 128) assert_raises(ValueError, gridder.pad_array, g, npd=npdt) prng = RandomState(12345) g = prng.rand(20) npdt = 16 assert_raises(ValueError, gridder.pad_array, g, npd=npdt)
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])
def test_serial_vs_parallel(): "gravmag.tesseroid serial and parallel execution give same result" model = TesseroidMesh((-1, 1.5, -2, 2, 0, -10e3), (3, 2, 1)) model.addprop('density', 500*np.ones(model.size)) lon, lat, height = gridder.regular((-1, 1.5, -2, 2), (15, 21), z=150e3) njobs = 3 for f in 'potential gx gy gz gxx gxy gxz gyy gyz gzz'.split(): func = getattr(tesseroid, f) serial = func(lon, lat, height, model, njobs=1) parallel = func(lon, lat, height, model, njobs=njobs) assert_allclose(serial, parallel, err_msg="Mismatch for {}".format(f))
def test_fails_if_npd_incorrect_dimension(): 'gridder.pad_array raises error if given improper dimension on npadding' s = (101, 172) x, y, z = gridder.regular((-5000., 5000., -5000., 5000.), s, z=-150) g = z.reshape(s) npdt = 128 assert_raises(ValueError, gridder.pad_array, g, npd=npdt) npdt = (128, 256, 142) assert_raises(ValueError, gridder.pad_array, g, npd=npdt) prng = RandomState(12345) g = prng.rand(50) assert_raises(ValueError, gridder.pad_array, g, npd=npdt)
def test_derivatives_uneven_shape(): "gravmag.transform FFT derivatives work if grid spacing is uneven" model = [Prism(-1000, 1000, -500, 500, 0, 2000, {'density': 100})] shape = (150, 300) x, y, z = gridder.regular([-10000, 10000, -10000, 10000], shape, z=-100) grav = utils.mgal2si(prism.gz(x, y, z, model)) analytical = prism.gzz(x, y, z, model) calculated = utils.si2eotvos(transform.derivz(x, y, grav, shape, method='fft')) diff = _trim(np.abs(analytical - calculated), shape) assert np.all(diff <= 0.005*np.abs(analytical).max()), \ "Failed for gzz"
def test_tilt_analytical_derivatives(): "gravmag.transform tilt returns same values given analytical derivatives" model = [Prism(-100, 100, -100, 100, 0, 100, {'density': 1000})] shape = (400, 400) x, y, z = gridder.regular([-10000, 10000, -10000, 10000], shape, z=-100) data = utils.mgal2si(prism.gz(x, y, z, model)) dx = utils.eotvos2si(prism.gxz(x, y, z, model)) dy = utils.eotvos2si(prism.gyz(x, y, z, model)) dz = utils.eotvos2si(prism.gzz(x, y, z, model)) tilt_analytical = transform.tilt(x, y, data, shape, dx, dy, dz) tilt_numerical = transform.tilt(x, y, data, shape) npt.assert_allclose(tilt_numerical, tilt_analytical, rtol=0.10)
def test_tilt_sane_values(): "gravmag.transform tilt returns sane values, between -90 and 90 degrees" inc, dec = 90, 0 mag = utils.ang2vec(200, inc, dec) model = [Prism(-500, 500, -500, 500, 0, 2000, {'magnetization': mag})] shape = (300, 300) x, y, z = gridder.regular([-10000, 10000, -10000, 10000], shape, z=-100) data = prism.tf(x, y, z, model, inc, dec) tilt = np.degrees(transform.tilt(x, y, data, shape)) assert tilt.max() < 90, \ "Maximum tilt greater than 90: {}".format(tilt.max()) assert tilt.min > -90, \ "Minimum tilt less than -90: {}".format(tilt.min())
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)
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))
def test_null_tesseroid(): "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(): 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))
def test_gx_derivatives(): "gravmag.transform FFT 1st derivatives of gx against analytical solutions" model = [Prism(-1000, 1000, -500, 500, 0, 2000, {'density': 100})] shape = (300, 300) x, y, z = gridder.regular([-10000, 10000, -10000, 10000], shape, z=-100) derivatives = 'x y z'.split() grav = utils.mgal2si(prism.gx(x, y, z, model)) for deriv in derivatives: analytical = getattr(prism, 'gx{}'.format(deriv))(x, y, z, model) calculated = utils.si2eotvos( getattr(transform, 'deriv' + deriv)(x, y, grav, shape, method='fft')) diff = _trim(np.abs(analytical - calculated), shape) assert np.all(diff <= 0.005*np.abs(analytical).max()), \ "Failed for gx{}".format(deriv)
def setup(): global model, x, y, z, inc, dec, struct_ind, field, xderiv, yderiv, \ zderiv, base, pos inc, dec = -30, 50 pos = np.array([1000, 1000, 200]) model = Sphere(pos[0], pos[1], pos[2], 1, {'magnetization': utils.ang2vec(10000, inc, dec)}) struct_ind = 3 shape = (128, 128) x, y, z = gridder.regular((0, 3000, 0, 3000), shape, z=-1) base = 10 field = utils.nt2si(sphere.tf(x, y, z, [model], inc, dec)) + base xderiv = fourier.derivx(x, y, field, shape) yderiv = fourier.derivy(x, y, field, shape) zderiv = fourier.derivz(x, y, field, shape)
def test_pad_and_unpad_equal_2d(): 'gridder.pad_array and subsequent .unpad_array gives original array: 2D' shape = (100, 101) x, y, z = gridder.regular((-5000., 5000., -5000., 5000.), shape, z=-150) # rosenbrock: (a-x)^2 + b(y-x^2)^2 a=1 b=100 usually X = x.reshape(shape) Y = y.reshape(shape) xy = [x, y] gz = scipy.optimize.rosen([Y/100000., X/100000.]) pads = ['mean', 'edge', 'lintaper', 'reflection', 'oddreflection', 'oddreflectiontaper', '0'] for p in pads: gpad, nps = gridder.pad_array(gz, padtype=p) gunpad = gridder.unpad_array(gpad, nps) assert_almost(gunpad, gz)
def test_laplace_from_potential(): "gravmag.transform 2nd derivatives of potential obey the Laplace equation" model = [Prism(-1000, 1000, -500, 500, 0, 2000, {'density': 200})] shape = (300, 300) x, y, z = gridder.regular([-10000, 10000, -10000, 10000], shape, z=-100) potential = prism.potential(x, y, z, model) gxx = utils.si2eotvos(transform.derivx(x, y, potential, shape, order=2, method='fft')) gyy = utils.si2eotvos(transform.derivy(x, y, potential, shape, order=2, method='fft')) gzz = utils.si2eotvos(transform.derivz(x, y, potential, shape, order=2)) laplace = _trim(gxx + gyy + gzz, shape) assert np.all(np.abs(laplace) <= 1e-10), \ "Max: {} Mean: {} STD: {}".format( laplace.max(), laplace.mean(), laplace.std())
def setup(): global model, x, y, z, inc, dec, struct_ind, field, xderiv, yderiv, zderiv, base, pos inc, dec = -30, 50 pos = np.array([1000, 1200, 200]) model = Sphere(pos[0], pos[1], pos[2], 1, {"magnetization": utils.ang2vec(10000, inc, dec)}) struct_ind = 3 shape = (200, 200) x, y, z = gridder.regular((0, 3000, 0, 3000), shape, z=-100) base = 10 field = sphere.tf(x, y, z, [model], inc, dec) + base # Use finite difference derivatives so that these tests don't depend on the # performance of the FFT derivatives. xderiv = (sphere.tf(x + 1, y, z, [model], inc, dec) - sphere.tf(x - 1, y, z, [model], inc, dec)) / 2 yderiv = (sphere.tf(x, y + 1, z, [model], inc, dec) - sphere.tf(x, y - 1, z, [model], inc, dec)) / 2 zderiv = (sphere.tf(x, y, z + 1, [model], inc, dec) - sphere.tf(x, y, z - 1, [model], inc, dec)) / 2
def test_horizontal_derivatives_fd(): "gravmag.transform 1st xy derivatives by finite diff against analytical" model = [Prism(-1000, 1000, -500, 500, 0, 2000, {'density': 100})] shape = (300, 300) x, y, z = gridder.regular([-5000, 5000, -5000, 5000], shape, z=-200) derivatives = 'x y'.split() grav = utils.mgal2si(prism.gz(x, y, z, model)) for deriv in derivatives: analytical = getattr(prism, 'g{}z'.format(deriv))(x, y, z, model) func = getattr(transform, 'deriv' + deriv) calculated = utils.si2eotvos(func(x, y, grav, shape, method='fd')) diff = np.abs(analytical - calculated) assert np.all(diff <= 0.005*np.abs(analytical).max()), \ "Failed for g{}. Max: {} Mean: {} STD: {}".format( deriv, diff.max(), diff.mean(), diff.std())
def test_coordinatevec_padding_2d(): 'gridder.padcoords accurately pads coordinate vector in 2D' shape = (101, 172) x, y, z = gridder.regular((-5000., 5000., -5000., 5000.), shape, z=-150) gz = np.zeros(shape) xy = [] xy.append(x) xy.append(y) gpad, nps = gridder.pad_array(gz) N = gridder.pad_coords(xy, gz.shape, nps) Yp = N[1].reshape(gpad.shape) Xp = N[0].reshape(gpad.shape) assert_equal(N[0].reshape(gpad.shape).shape, gpad.shape) assert_almost(Yp[nps[0][0]:-nps[0][1], nps[1][0]:-nps[1][1]].ravel(), y) assert_almost(Xp[nps[0][0]:-nps[0][1], nps[1][0]:-nps[1][1]].ravel(), x)
def test_pole_reduce(): "gravmag.transform pole reduction matches analytical solution" # Use remanent magnetization sinc, sdec = -70, 30 model = [Prism(-100, 100, -500, 500, 0, 100, {'density': 1000, 'magnetization': utils.ang2vec(5, sinc, sdec)})] # Use low latitudes to make sure that there are no problems with FFT # instability. inc, dec = -60, -15 shape = (50, 50) x, y, z = gridder.regular([-2000, 2000, -2000, 2000], shape, z=-100) data = prism.tf(x, y, z, model, inc, dec) pole = transform.reduce_to_pole(x, y, data, shape, inc, dec, sinc, sdec) pole_true = prism.tf(x, y, z, model, -90, 0, pmag=utils.ang2vec(5, -90, 0)) npt.assert_allclose(pole, pole_true, atol=10, rtol=0.01)
def test_second_derivatives(): "gravmag.transform FFT second derivatives against analytical solutions" model = [Prism(-1000, 1000, -500, 500, 0, 2000, {'density': -200})] shape = (300, 300) x, y, z = gridder.regular([-10000, 10000, -10000, 10000], shape, z=-100) derivatives = 'xx yy zz'.split() pot = prism.potential(x, y, z, model) for deriv in derivatives: analytical = getattr(prism, 'g{}'.format(deriv))(x, y, z, model) calculated = utils.si2eotvos( getattr(transform, 'deriv' + deriv[0])(x, y, pot, shape, order=2, method='fft')) diff = _trim(np.abs(analytical - calculated), shape) assert np.all(diff <= 0.005*np.abs(analytical).max()), \ "Failed for g{}. Max: {} Mean: {} STD: {}".format( deriv, diff.max(), diff.mean(), diff.std())
def test_second_horizontal_derivatives_fd(): "gravmag.transform 2nd xy derivatives by finite diff against analytical" model = [Prism(-1000, 1000, -500, 500, 0, 2000, {'density': 100})] shape = (300, 300) x, y, z = gridder.regular([-10000, 10000, -10000, 10000], shape, z=-500) derivatives = 'xx yy'.split() grav = prism.potential(x, y, z, model) for deriv in derivatives: analytical = getattr(prism, 'g{}'.format(deriv))(x, y, z, model) func = getattr(transform, 'deriv' + deriv[0]) calculated = utils.si2eotvos(func(x, y, grav, shape, method='fd', order=2)) diff = np.abs(analytical - calculated) assert np.all(diff/np.abs(analytical).max() <= 0.01), \ "Failed for g{}. Max: {} Mean: {} STD: {}".format( deriv, diff.max(), diff.mean(), diff.std())
mpl.subplot(2, 1, 1) mpl.axis('scaled') mpl.title('Density (mass)') mpl.pcolor(grid.y, grid.x, grid.props['density'], grid.shape) mpl.colorbar() mpl.subplot(2, 1, 2) mpl.axis('scaled') mpl.title('Magnetization intensity (dipole moment)') mpl.pcolor(grid.y, grid.x, utils.vecnorm(grid.props['magnetization']), grid.shape) mpl.colorbar() mpl.show() # Now do some calculations with the grid shape = (100, 100) x, y, z = gridder.regular(grid.area, shape, z=0) gz = sphere.gz(x, y, z, grid) tf = sphere.tf(x, y, z, grid, inc, dec) mpl.figure() mpl.subplot(2, 1, 1) mpl.axis('scaled') mpl.title('Gravity anomaly') mpl.contourf(y, x, gz, shape, 30) mpl.colorbar() mpl.subplot(2, 1, 2) mpl.axis('scaled') mpl.title('Magnetic total field anomaly') mpl.contourf(y, x, tf, shape, 30) mpl.colorbar() mpl.show()
""" GravMag: Use the Polynomial Equivalent Layer to reduce a magnetic total field anomaly to the pole """ from fatiando import gravmag, gridder, utils, mesher from fatiando.vis import mpl # Make synthetic data inc, dec = -60, 23 props = {'magnetization': 10} model = [mesher.Prism(-500, 500, -1000, 1000, 500, 4000, props)] shape = (50, 50) x, y, z = gridder.regular([-5000, 5000, -5000, 5000], shape, z=-150) tf = utils.contaminate(gravmag.prism.tf(x, y, z, model, inc, dec), 5) # Setup the layer grid = mesher.PointGrid([-5000, 5000, -5000, 5000], 200, (100, 100)) # Wrape the data data = [gravmag.eqlayer.TotalField(x, y, z, tf, inc, dec)] # Calculate the magnetization intensity # PEL returns the matrices it computes so that you can re-calculate with # different smoothness and damping at very low cost intensity, matrices = gravmag.eqlayer.pel(data, grid, (20, 20), degree=1, smoothness=10.**-2) grid.addprop('magnetization', intensity) # Compute the predicted data and the residuals predicted = gravmag.sphere.tf(x, y, z, grid, inc, dec) residuals = tf - predicted print "Residuals:" print "mean:", residuals.mean()
""" Meshing: Generate a 3D prism model of the topography """ from fatiando import gridder, utils, mesher from fatiando.vis import myv area = (-150, 150, -300, 300) shape = (100, 50) x, y = gridder.regular(area, shape) height = (-80 * utils.gaussian2d(x, y, 100, 200, x0=-50, y0=-100, angle=-60) + 100 * utils.gaussian2d(x, y, 50, 100, x0=80, y0=170)) nodes = (x, y, -1 * height) # -1 is to convert height to z coordinate reference = 0 # z coordinate of the reference surface relief = mesher.PrismRelief(reference, gridder.spacing(area, shape), nodes) relief.addprop('density', (2670 for i in xrange(relief.size))) myv.figure() myv.prisms(relief, prop='density', edges=False) axes = myv.axes(myv.outline()) myv.wall_bottom(axes.axes.bounds, opacity=0.2) myv.wall_north(axes.axes.bounds) myv.show()
plt.legend() p12x = [p1[0], p2[0]] p12y = [p1[1], p2[1]] plt.plot(p12x, p12y, c='red') p12v = plt.scatter(p12x, p12y, c='red') txt = ['p1', 'p2'] for i in range(len(p12x)): plt.annotate(txt[i], (p12x[i], p12y[i]), c='red') plt.xlabel('x (m)') plt.ylabel('y (m)') prl = 60 # shape = shape (max(xp)-min(xp))/ # shape = (115,115) xint_scipy, yint_scipy = gridder.regular( (min(xp) - prl, max(xp) + prl, min(yp) - prl, max(yp) + prl), shape=shape) #%% Solution 1 # extrapolate False and fill with 0 before derivative - mask them later on U_int_scipy = gridder.interp_at(xp, yp, U, xint_scipy, yint_scipy, algorithm='cubic', extrapolate=False) InterpData = np.array([xint_scipy, yint_scipy, U_int_scipy]).T where_are_NaNs = np.isnan(InterpData) InterpData[where_are_NaNs] = 0.0074 xint_scipy, yint_scipy, U_int_scipy = InterpData.T
def load_surfer(fname, dtype='float64'): """ Read data from a Surfer ASCII grid file. Surfer is a contouring, griding and surface mapping software from GoldenSoftware. The names and logos for Surfer and Golden Software are registered trademarks of Golden Software, Inc. http://www.goldensoftware.com/products/surfer Parameters: * fname : str Name of the Surfer grid file * dtype : numpy dtype object or string The type of variable used for the data. Default is numpy.float64. Use numpy.float32 if the data are large and precision is not an issue. Returns: * data : dict The data in a dictionary with some metadata: * ``'file'`` : string The name of the original data file * ``'shape'`` : tuple (nx, ny), the number of grid points in x (North) and y (East) * ``'area'`` : tuple (x1, x2, y1, y2), the spacial limits of the grid. * ``'x'`` : 1d-array Value of the North-South coordinate of each grid point. * ``'y'`` : 1d-array Value of the East-West coordinate of each grid point. * ``'data'`` : 1d-array Values of the field in each grid point. Field can be for example topography, gravity anomaly, etc. If any field values are >= 1.70141e+38 (Surfers way of marking NaN values), the array will be masked at those values (i.e., ``'data'`` will be a numpy masked array). """ # Surfer ASCII grid structure # DSAA Surfer ASCII GRD ID # nCols nRows number of columns and rows # xMin xMax X min max # yMin yMax Y min max # zMin zMax Z min max # z11 z21 z31 ... List of Z values with open(fname) as input_file: # DSAA is a Surfer ASCII GRD ID (discard it for now) input_file.readline() # Read the number of columns (ny) and rows (nx) ny, nx = [int(s) for s in input_file.readline().split()] shape = (nx, ny) # Our x points North, so the first thing we read is y, not x. ymin, ymax = [float(s) for s in input_file.readline().split()] xmin, xmax = [float(s) for s in input_file.readline().split()] area = (xmin, xmax, ymin, ymax) dmin, dmax = [float(s) for s in input_file.readline().split()] field = np.fromiter( (float(s) for line in input_file for s in line.split()), dtype=dtype) nans = field >= 1.70141e+38 if np.any(nans): field = np.ma.masked_where(nans, field) err_msg = "{} of data ({}) doesn't match one from file ({})." assert np.allclose(dmin, field.min()), err_msg.format( 'Min', dmin, field.min()) assert np.allclose(dmax, field.max()), err_msg.format( 'Max', dmax, field.max()) x, y = gridder.regular(area, shape) data = dict(file=fname, shape=shape, area=area, data=field, x=x, y=y) return data
------------- You can create the (x, y, z) coordinate arrays for regular grids using :func:`fatiando.gridder.regular`. """ from __future__ import print_function from fatiando import gridder import matplotlib.pyplot as plt # Define the area of the grid in meters: [x1, x2, y1, y2] area = [0, 10e3, -5e3, 5e3] # The shape is the number of points in the grid: (nx, ny) shape = (5, 9) x, y = gridder.regular(area, shape) # x and y are 1d arrays with the coordinates of each point in the grid print('x =', x) print('y =', y) # Optionally, you can generate a 3rd array with constant z values # (remember that z is positive downward) x, y, z = gridder.regular(area, shape, z=-150) print('z =', z) plt.figure(figsize=(6, 5)) plt.title('Regular grid') # In Fatiando, x is North and y is East. # So we should plot x in the vertical axis and y in horizontal. plt.plot(y, x, 'ok')
area = (-2, 2, -2, 2) x, y = gridder.scatter(area, n=200, seed=0) # And calculate 2D Gaussians on these points as sample data def data(x, y): return (utils.gaussian2d(x, y, -0.6, -1) - utils.gaussian2d(x, y, 1.5, 1.5)) z = data(x, y) shape = (100, 100) # First, we need to know the real data at the grid points grdx, grdy = gridder.regular(area, shape) grdz = data(grdx, grdy) mpl.figure() mpl.subplot(2, 2, 1) mpl.axis('scaled') mpl.title("True grid data") mpl.plot(x, y, '.k', label='Data points') mpl.contourf(grdx, grdy, grdz, shape, 50) mpl.colorbar() mpl.legend(loc='lower right', numpoints=1) # Use the default interpolation (cubic) grdx, grdy, grdz = gridder.interp(x, y, z, shape) mpl.subplot(2, 2, 2) mpl.axis('scaled') mpl.title("Interpolated using cubic minimum-curvature")
""" Gridding: Cut a section from a grid """ from fatiando import gridder, utils from fatiando.vis import mpl # Generate some synthetic data on a regular grid x, y = gridder.regular((-10, 10, -10, 10), (100, 100)) # Using a 2D Gaussian z = utils.gaussian2d(x, y, 1, 1) subarea = [-2, 2, -3, 3] subx, suby, subscalar = gridder.cut(x, y, [z], subarea) mpl.figure(figsize=(12, 5)) mpl.subplot(1, 2, 1) mpl.title("Whole grid") mpl.axis('scaled') mpl.pcolor(x, y, z, (100, 100)) mpl.square(subarea, 'k', linewidth=2, label='Cut this region') mpl.legend(loc='lower left') mpl.subplot(1, 2, 2) mpl.title("Cut grid") mpl.axis('scaled') mpl.pcolor(subx, suby, subscalar[0], (40, 60), interp=True) mpl.show()
""" Meshing: Make and plot a tesseroid mesh with topography """ from fatiando import gridder, utils, mesher from fatiando.vis import myv w, e = -2, 2 s, n = -2, 2 bounds = (w, e, s, n, 500000, 0) x, y = gridder.regular((w, e, s, n), (50, 50)) height = (250000 + -100000 * utils.gaussian2d(x, y, 1, 5, x0=-1, y0=-1, angle=-60) + 250000 * utils.gaussian2d(x, y, 1, 1, x0=0.8, y0=1.7)) mesh = mesher.TesseroidMesh(bounds, (20, 50, 50)) mesh.carvetopo(x, y, height) scene = myv.figure(zdown=False) myv.tesseroids(mesh) myv.earth(opacity=0.3) myv.continents() scene.scene.camera.position = [ 21592740.078245595, 22628783.944262519, -28903782.916664094 ] scene.scene.camera.focal_point = [ 5405474.2152075395, -1711034.715136874, 2155879.3486608281 ] scene.scene.camera.view_angle = 1.6492674416639987 scene.scene.camera.view_up = [ 0.91713422625547714, -0.1284658947859818, 0.37730799740742887
being generally inferior to an inversion result. Here we'll show how the Generalized Inverse imaging method can be used on some synthetic data. We'll plot the final result as slices across the x, y, z axis. """ from __future__ import division from fatiando import gridder, mesher from fatiando.gravmag import prism, imaging from fatiando.vis.mpl import square import matplotlib.pyplot as plt import numpy as np # Make some synthetic gravity data from a simple prism model model = [mesher.Prism(-1000, 1000, -3000, 3000, 0, 2000, {'density': 800})] shape = (25, 25) xp, yp, zp = gridder.regular((-5000, 5000, -5000, 5000), shape, z=-10) data = prism.gz(xp, yp, zp, model) # Run the Generalized Inverse mesh = imaging.geninv(xp, yp, zp, data, shape, zmin=0, zmax=5000, nlayers=25) # Plot the results fig = plt.figure() X, Y = xp.reshape(shape) / 1000, yp.reshape(shape) / 1000 image = mesh.props['density'].reshape(mesh.shape) # First plot the original gravity data ax = plt.subplot(2, 2, 1) ax.set_title('Gravity data (mGal)') ax.set_aspect('equal')
log.info("Fetching CRUST2.0 model") archive = io.fetch_crust2() log.info("Converting to tesseroids") model = io.crust2_to_tesseroids(archive) log.info(' model size: %d' % (len(model))) # Plot the tesseroid model myv.figure(zdown=False) myv.tesseroids(model, 'density') myv.continents(linewidth=3) myv.show() # Make the computation grid area = (-180, 180, -80, 80) shape = (100, 100) lons, lats, heights = gridder.regular(area, shape, z=250000) # Divide the model into nproc slices and calculate them in parallel log.info('Calculating...') def calculate(chunk): return gravmag.tesseroid.gz(lons, lats, heights, chunk) def split(model, nproc): chunksize = len(model) / nproc for i in xrange(nproc - 1): yield model[i * chunksize:(i + 1) * chunksize] yield model[(nproc - 1) * chunksize:]
sediments["bottom"] = sediments_top - sediments["thickness"] # Create Tesseroids model of the sediments layer # ---------------------------------------------- bottom, top = sediments["bottom"].copy(), sediments["top"].copy() top[nans] = 0 bottom[nans] = 0 basin = TesseroidModel(sediments['area'], top, bottom, sediments['shape']) # Create computation grid at 10km above the spheroid # -------------------------------------------------- shape = (79, 81) area = (-40.8, -33., 287, 295.) lat, lon, height = gridder.regular(area, shape, z=10e3) grid = {'lat': lat, 'lon': lon, 'height': height, 'shape': shape, 'area': area} # Common variables between computations # ------------------------------------- # Define density values for the top and the bottom of the sediment layer density_top, density_bottom = -412, -275 # Define top and bottom variables as the maximum and minimum sediments' # height and depth, respectively top, bottom = basin.top[~nans].max(), basin.bottom[~nans].min() print("Top of sediments: {} \nBottom of sediments: {}".format(top, bottom))
p1, p2 = p rot = 60 origin = (max(xp), min(yp)) point_torotate = np.array([xp, yp]) xp_r, yp_r = MALM_pm.rotate_60(origin, point_torotate, angle_deg=rot, showfig=False) Xs = xp_r - min(xp_r) Ys = yp_r - min(yp_r) prl = 60 # shape = shape (max(xp)-min(xp))/ shape = (150, 150) xint_scipy, yint_scipy = gridder.regular( (min(Xs) - prl, max(Xs) + prl, min(Ys) - prl, max(Ys) + prl), shape=shape) #%% ------------------------------- MALM DATA real MainPath = r'E:\Padova\Software\SourceInversion\Potential_field_imaging\dEXP_imaging\examples_in_prep\\' # os.chdir(MainPath) ## --------- read MALM measured data file (with electrode positions) --------- ## # RealData = np.loadtxt("./1_Data_2_plot/to_plot.dat",skiprows=0,delimiter='\t') out = MALM_pm.load_MALM_Porto_real(MainPath + '/malm_models/', MainPath + './malm_models/XYObs_real_f_m3.txt', shape=(100, 100), radius=200, rcor=10, rot=0, showfig=False)
import sys from matplotlib import pyplot import numpy from fatiando.mesher.dd import Square from fatiando.seismic import epicenter, traveltime from fatiando import vis, utils, inversion, gridder, ui import cPickle as pickle with open('dados.pickle') as f: recs, src, ttr, error = pickle.load(f) area = (0, 100000, 0, 100000) vp, vs = 2000, 1000 shape = (50, 50) xs, ys = gridder.regular(area, shape) goals = epicenter.mapgoal(xs, ys, ttr, recs, vp, vs) pyplot.figure() ax = pyplot.subplot(1, 1, 1) pyplot.axis('scaled') pyplot.suptitle("Escolha a estimativa inicial") vis.map.contourf(xs, ys, goals, shape, 30) vis.map.points(recs, '^r') vis.map.points(src, '*y') inicial = ui.picker.points(area, ax, marker='*', color='k')[0] solver = inversion.gradient.newton(initial=inicial) result = epicenter.flat_earth(ttr, recs, vp, vs, solver) estimate, residuals = result predicted = ttr - residuals
""" Vis: Plot a map using the Mercator map projection and pseudo-color """ from fatiando import gridder, utils, vis # Generate some data to plot area = (-20, 40, 20, 80) shape = (100, 100) lon, lat = gridder.regular(area, shape) data = utils.gaussian2d(lon, lat, 10, 20, 10, 60, angle=45) # Now get a basemap to plot with some projection bm = vis.mpl.basemap(area, 'merc') # And now plot everything passing the basemap to the plotting functions vis.mpl.figure(figsize=(5, 8)) vis.mpl.pcolor(lon, lat, data, shape, basemap=bm) vis.mpl.colorbar() bm.drawcoastlines() bm.drawmapboundary() bm.drawcountries() vis.mpl.draw_geolines(area, 10, 10, bm) vis.mpl.show()
""" GravMag: Forward modeling of the gravity anomaly using tesseroids in parallel using ``multiprocessing`` """ import time from multiprocessing import Pool from fatiando import gravmag, gridder, utils from fatiando.mesher import Tesseroid 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
GravMag: Upward continuation of noisy gz data """ from fatiando import mesher, gridder, utils from fatiando.gravmag import prism, transform from fatiando.vis import mpl import numpy as np model = [ mesher.Prism(-3000, -2000, -3000, -2000, 500, 2000, {'density': 1000}), mesher.Prism(-1000, 1000, -1000, 1000, 0, 2000, {'density': -800}), mesher.Prism(1000, 3000, 2000, 3000, 0, 1000, {'density': 900}) ] area = (-5000, 5000, -5000, 5000) shape = (50, 50) z0 = -100 x, y, z = gridder.regular(area, shape, z=z0) gz = utils.contaminate(prism.gz(x, y, z, model), 0.5, seed=0) height = 1000 # How much higher to go gzcontf = transform.upcontinue(x, y, gz, shape, height) # Compute the true value at the new height for comparison gztrue = prism.gz(x, y, z - height, model) args = dict(shape=shape, levels=20, cmap=mpl.cm.RdBu_r) fig, axes = mpl.subplots(1, 3, figsize=(12, 3.5)) axes = axes.ravel() mpl.sca(axes[0]) mpl.title("Original") mpl.axis('scaled') mpl.contourf(x, y, gz, **args)
""" from fatiando.mesher import Prism from fatiando import gridder, utils from fatiando.gravmag import prism, transform from fatiando.gravmag.euler import Classic from fatiando.vis import mpl, myv # The regional field inc, dec = -45, 0 # Make a model bounds = [-5000, 5000, -5000, 5000, 0, 5000] model = [Prism(-1500, -500, -500, 500, 1000, 2000, {'magnetization': 2})] # Generate some data from the model shape = (200, 200) area = bounds[0:4] xp, yp, zp = gridder.regular(area, shape, z=-1) # Add a constant baselevel baselevel = 10 # Convert from nanoTesla to Tesla because euler and derivatives require things # in SI tf = (utils.nt2si(prism.tf(xp, yp, zp, model, inc, dec)) + baselevel) # Calculate the derivatives using FFT xderiv = transform.derivx(xp, yp, tf, shape) yderiv = transform.derivy(xp, yp, tf, shape) zderiv = transform.derivz(xp, yp, tf, shape) mpl.figure() titles = ['Total field', 'x derivative', 'y derivative', 'z derivative'] for i, f in enumerate([tf, xderiv, yderiv, zderiv]): mpl.subplot(2, 2, i + 1) mpl.title(titles[i])
""" GravMag: 3D imaging using the migration method on synthetic gravity data (simple model) """ from fatiando import gridder, mesher, gravmag from fatiando.vis import mpl, myv # Make some synthetic gravity data from a simple prism model prisms = [mesher.Prism(-1000, 1000, -2000, 2000, 2000, 4000, {'density': 500})] shape = (50, 50) xp, yp, zp = gridder.regular((-10000, 10000, -10000, 10000), shape, z=-10) gz = gravmag.prism.gz(xp, yp, zp, prisms) # Plot the data mpl.figure() mpl.axis('scaled') mpl.contourf(yp, xp, gz, shape, 30) mpl.colorbar() mpl.xlabel('East (km)') mpl.ylabel('North (km)') mpl.m2km() mpl.show() mesh = gravmag.imaging.migrate(xp, yp, zp, gz, 0, 10000, (25, 25, 25)) # Plot the results myv.figure() myv.prisms(prisms, 'density', style='wireframe', linewidth=2) myv.prisms(mesh, 'density', edges=False) axes = myv.axes(myv.outline()) myv.wall_bottom(axes.axes.bounds)
""" Meshing: Make and plot a 3D prism mesh with topography """ from fatiando import gridder, utils, mesher from fatiando.vis import myv x1, x2 = -100, 100 y1, y2 = -200, 200 bounds = (x1, x2, y1, y2, -200, 0) x, y = gridder.regular((x1, x2, y1, y2), (50, 50)) height = (100 + -50 * utils.gaussian2d(x, y, 100, 200, x0=-50, y0=-100, angle=-60) + 100 * utils.gaussian2d(x, y, 50, 100, x0=80, y0=170)) mesh = mesher.PrismMesh(bounds, (20, 40, 20)) mesh.carvetopo(x, y, height) myv.figure() myv.prisms(mesh) myv.axes(myv.outline(bounds), fmt='%.0f') myv.wall_north(bounds) myv.show()
for key in cdir: if case == key and i == cdir.get(key): return 10 return 0 # The test cases as string list cases = ['above', 'below', 'north', 'south', 'east', 'west'] # Create reference model bounds = (0, 3, 0, 3, 0, 3) shape = (3, 3, 3) shapegz = (10, 10) for testcase in cases: mref = PrismMesh(bounds, shape) mesh = mref.copy() mref.addprop('density', [fill(i, testcase) for i in xrange(mref.size)]) # Calculate reference gravity field xp, yp, zp = gridder.regular(bounds[:4], shapegz, z=-1) gzref = prism.gz(xp, yp, zp, mref) # Initiate harvest hgref = [harvester.Gz(xp, yp, zp, gzref)] loc = [[1.5, 1.5, 1.5, {'density': 10}]] seeds = harvester.sow(loc, mesh) # est0 should be incorrect and thus fail wilst est1 should yield the # same geometry as mref est0, pred0 = harvester.harvest(hgref, seeds, mesh, compactness=0.1, threshold=0.001, restrict=[testcase]) est1, pred1 = harvester.harvest(hgref, seeds, mesh, compactness=0.1, threshold=0.001) res0 = mesh.copy() res0.addprop('density', est0['density']) res1 = mesh.copy() res1.addprop('density', est1['density'])