def test_eql_grav_jacobian(): "EQLGravity produces the right Jacobian matrix for single source" model = PointGrid([-10, 10, -10, 10], 500, (2, 2))[0] model.addprop('density', 1) n = 1000 x, y, z = gridder.scatter([-10, 10, -10, 10], n, z=-100, seed=42) data = sphere.gz(x, y, z, [model]) eql = EQLGravity(x, y, z, data, [model]) A = eql.jacobian(None) assert A.shape == (n, 1) assert_allclose(A[:, 0], data, rtol=0.01)
def test_eqlgrav_prism_interp(): "EQLGravity can interpolate data from a prism" model = [Prism(-300, 300, -500, 500, 100, 600, {'density': 400})] shape = (30, 30) n = shape[0]*shape[1] area = [-2000, 2000, -2000, 2000] x, y, z = gridder.scatter(area, n, z=-100, seed=42) data = prism.gz(x, y, z, model) layer = PointGrid(area, 200, shape) eql = EQLGravity(x, y, z, data, layer) + 1e-23*Damping(layer.size) eql.fit() layer.addprop('density', eql.estimate_) assert_allclose(eql[0].predicted(), data, rtol=0.01) xp, yp, zp = gridder.regular(area, shape, z=-100) true = prism.gz(xp, yp, zp, model) calc = sphere.gz(xp, yp, zp, layer) assert_allclose(calc, true, rtol=0.05)
def test_gz_sphere(): ''' This test compare the results obtained by both function that calculates the vertical gravitational attraction due to a solid sphere. The model has the same dimensions and same value for the density. We use the function from Fatiando a Terra in order to compare with our function. ''' density = 1500. # Modelo para o Fatiando xp, yp, zp = gridder.regular((-1000, 1000, -1000, 1000), (200, 200), z=-345.) model = [mesher.Sphere(-100., 400., 550., 380., {'density': density})] gz = sphere.gz(xp, yp, zp, model) gz = gz.reshape(200, 200) # Modelo para minha funcao x, y = numpy.meshgrid(numpy.linspace(-1000., 1000., 200), numpy.linspace(-1000., 1000., 200)) z = -345. * numpy.ones((200, 200)) mymodel = [-100., 400., 550., 380., density] mygz = sphere_gz(y, x, z, mymodel) assert_almost_equal(gz, mygz, decimal=5)
def test_pelgrav_prism_interp(): "PELGravity can interpolate data from a prism" model = [Prism(-300, 300, -500, 500, 100, 600, {'density': 400})] shape = (40, 40) n = shape[0]*shape[1] area = [-2000, 2000, -2000, 2000] x, y, z = gridder.scatter(area, n, z=-100, seed=42) data = prism.gz(x, y, z, model) layer = PointGrid(area, 100, shape) windows = (20, 20) degree = 1 eql = (PELGravity(x, y, z, data, layer, windows, degree) + 5e-22*PELSmoothness(layer, windows, degree)) eql.fit() layer.addprop('density', eql.estimate_) assert_allclose(eql[0].predicted(), data, rtol=0.01) xp, yp, zp = gridder.regular(area, shape, z=-100) true = prism.gz(xp, yp, zp, model) calc = sphere.gz(xp, yp, zp, layer) assert_allclose(calc, true, atol=0.001, rtol=0.05)
# Estimate the density using enough damping so that won't try to fit the error eql = EQLGravity(x, y, z, gz, layer) + 1e-22 * Damping(layer.size) eql.fit() # Now we add the estimated densities to our layer layer.addprop('density', eql.estimate_) # and print some statistics of how well the estimated layer fits the data residuals = eql[0].residuals() print("Residuals:") print(" mean:", residuals.mean(), 'mGal') print(" stddev:", residuals.std(), 'mGal') # Now I can forward model gravity data anywhere we want. For interpolation, we # calculate it on a grid. For upward continuation, at a greater height. We can # even combine both into a single operation. x2, y2, z2 = gridder.regular(area, (50, 50), z=-1000) gz_up = sphere.gz(x2, y2, z2, layer) fig, axes = plt.subplots(1, 2, figsize=(8, 6)) ax = axes[0] ax.set_title('Original data') ax.set_aspect('equal') tmp = ax.tricontourf(y / 1000, x / 1000, gz, 30, cmap='cubehelix_r') fig.colorbar(tmp, ax=ax, pad=0.1, aspect=30, orientation='horizontal').set_label('mGal') ax.plot(y / 1000, x / 1000, 'xk') ax.set_xlabel('y (km)') ax.set_ylabel('x (km)') ax = axes[1] ax.set_title('Gridded and upward continued')
def test_gz(): "gravmag.sphere.gz python vs cython implementation" py = _sphere_numpy.gz(xp, yp, zp, model) cy = sphere.gz(xp, yp, zp, model) diff = np.abs(py - cy) assert np.all(diff <= precision), 'max diff: %g' % (max(diff))
def sensitivity(self, grid): x, y, z = self.x, self.y, self.z sens = numpy.empty((self.size, len(grid)), dtype=float) for i, s in enumerate(grid): sens[:, i] = kernel.gz(x, y, z, [s], dens=1.) return sens
# Estimate the density # Need to apply enough damping so that won't try to fit the error as well misfit = EQLGravity(x, y, z, gz, layer) regul = Damping(layer.size) # Use an L-curve analysis to find the best regularization parameter solver = LCurve(misfit, regul, [10**i for i in range(-30, -20)]).fit() layer.addprop('density', solver.estimate_) residuals = solver.residuals() print "Residuals:" print "mean:", residuals.mean() print "stddev:", residuals.std() # Now I can forward model the layer at a greater height and check against the # true solution of the prism gz_true = prism.gz(x, y, z - 500, model) gz_up = sphere.gz(x, y, z - 500, layer) mpl.figure() mpl.suptitle('L-curve') mpl.title("Estimated regularization parameter: %g" % (solver.regul_param_)) solver.plot_lcurve() mpl.grid() mpl.figure(figsize=(14, 4)) mpl.subplot(1, 3, 1) mpl.axis('scaled') mpl.title('Layer (kg.m^-3)') mpl.pcolor(layer.y, layer.x, layer.props['density'], layer.shape) mpl.colorbar() mpl.m2km() mpl.subplot(1, 3, 2)
# and the inversion # Apply a scaling factor to make both portions of the misfit the same order of # magnitude scale = np.linalg.norm(gz)**2 / np.linalg.norm(gzz)**2 misfit = (EQLGravity(x1, y1, z1, gz, layer) + scale * EQLGravity(x2, y2, z2, gzz, layer, field='gzz')) regul = Smoothness2D(layer.shape) # Use an L-curve analysis to find the best regularization parameter solver = LCurve(misfit, regul, [10**i for i in range(-30, -20)]).fit() layer.addprop('density', solver.estimate_) # Now I can forward model gz using my layer to produce an integrated map in a # much denser region shape = (50, 50) x, y, z = gridder.regular(area, shape, z=0) gz_layer = sphere.gz(x, y, z, layer) gz_true = prism.gz(x, y, z, model) mpl.figure() mpl.suptitle('L-curve') mpl.title("Estimated regularization parameter: %g" % (solver.regul_param_)) solver.plot_lcurve() mpl.grid() # Plot the layer and the fit mpl.figure(figsize=(14, 4)) mpl.suptitle('Observed data (black) | Predicted by layer (red)') mpl.subplot(1, 3, 1) mpl.axis('scaled') mpl.title('Layer (kg.m^-3)') mpl.pcolor(layer.y, layer.x, layer.props['density'], layer.shape)
""" GravMag: Forward modeling of the gravity anomaly and gravity gradient tensor using model """ from fatiando import mesher, gridder from fatiando.gravmag import sphere from fatiando.vis import mpl model = [mesher.Sphere(0, 0, 2000, 1000, {'density': 1000})] area = (-5000, 5000, -5000, 5000) shape = (100, 100) x, y, z = gridder.regular(area, shape, z=-100) gz = sphere.gz(x, y, z, model) tensor = [ sphere.gxx(x, y, z, model), sphere.gxy(x, y, z, model), sphere.gxz(x, y, z, model), sphere.gyy(x, y, z, model), sphere.gyz(x, y, z, model), sphere.gzz(x, y, z, model) ] mpl.figure() mpl.axis('scaled') mpl.title('gz') mpl.contourf(y, x, gz, shape, 15) mpl.colorbar() mpl.m2km() mpl.figure() titles = ['gxx', 'gxy', 'gxz', 'gyy', 'gyz', 'gzz'] for i, field in enumerate(tensor): mpl.subplot(2, 3, i + 1)
# Create a model using geometric objects from fatiando.mesher # Each model element has a dictionary with its physical properties. # We'll use two spheres with opposite density contrast values. model = [mesher.Sphere(x=10e3, y=10e3, z=1.5e3, radius=1.5e3, props={'density': 500}), mesher.Sphere(x=20e3, y=20e3, z=1.5e3, radius=1.5e3, props={'density': -500})] # Create a regular grid at a constant height shape = (300, 300) area = [0, 30e3, 0, 30e3] x, y, z = gridder.regular(area, shape, z=-100) fields = [ ['Gravity (mGal)', sphere.gz(x, y, z, model)], ['gxx (Eotvos)', sphere.gxx(x, y, z, model)], ['gyy (Eotvos)', sphere.gyy(x, y, z, model)], ['gzz (Eotvos)', sphere.gzz(x, y, z, model)], ['gxy (Eotvos)', sphere.gxy(x, y, z, model)], ['gxz (Eotvos)', sphere.gxz(x, y, z, model)], ['gyz (Eotvos)', sphere.gyz(x, y, z, model)], ] # Make maps of all fields calculated fig = plt.figure(figsize=(10, 8)) plt.rcParams['font.size'] = 10 X, Y = x.reshape(shape)/1000, y.reshape(shape)/1000 for i, tmp in enumerate(fields): ax = plt.subplot(3, 3, i + 3) field, data = tmp
# and the inversion # Apply a scaling factor to make both portions of the misfit the same order of # magnitude scale = np.linalg.norm(gz) ** 2 / np.linalg.norm(gzz) ** 2 misfit = (EQLGravity(x1, y1, z1, gz, layer) + scale * EQLGravity(x2, y2, z2, gzz, layer, field='gzz')) regul = Smoothness2D(layer.shape) # Use an L-curve analysis to find the best regularization parameter solver = LCurve(misfit, regul, [10 ** i for i in range(-30, -20)]).fit() layer.addprop('density', solver.estimate_) # Now I can forward model gz using my layer to produce an integrated map in a # much denser region shape = (50, 50) x, y, z = gridder.regular(area, shape, z=0) gz_layer = sphere.gz(x, y, z, layer) gz_true = prism.gz(x, y, z, model) mpl.figure() mpl.suptitle('L-curve') mpl.title("Estimated regularization parameter: %g" % (solver.regul_param_)) solver.plot_lcurve() mpl.grid() # Plot the layer and the fit mpl.figure(figsize=(14, 4)) mpl.suptitle('Observed data (black) | Predicted by layer (red)') mpl.subplot(1, 3, 1) mpl.axis('scaled') mpl.title('Layer (kg.m^-3)') mpl.pcolor(layer.y, layer.x, layer.props['density'], layer.shape)
def sensitivity(self, grid): x, y, z = self.x, self.y, self.z sens = numpy.empty((self.size, len(grid)), dtype=float) for i, s in enumerate(grid): sens[:,i] = kernel.gz(x, y, z, [s], dens=1.) return sens
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()
radius=1.5e3, props={'density': 500}), mesher.Sphere(x=20e3, y=20e3, z=1.5e3, radius=1.5e3, props={'density': -500}) ] # Create a regular grid at a constant height shape = (300, 300) area = [0, 30e3, 0, 30e3] x, y, z = gridder.regular(area, shape, z=-100) fields = [ ['Gravity (mGal)', sphere.gz(x, y, z, model)], ['gxx (Eotvos)', sphere.gxx(x, y, z, model)], ['gyy (Eotvos)', sphere.gyy(x, y, z, model)], ['gzz (Eotvos)', sphere.gzz(x, y, z, model)], ['gxy (Eotvos)', sphere.gxy(x, y, z, model)], ['gxz (Eotvos)', sphere.gxz(x, y, z, model)], ['gyz (Eotvos)', sphere.gyz(x, y, z, model)], ] # Make maps of all fields calculated fig = plt.figure(figsize=(10, 8)) plt.rcParams['font.size'] = 10 X, Y = x.reshape(shape) / 1000, y.reshape(shape) / 1000 for i, tmp in enumerate(fields): ax = plt.subplot(3, 3, i + 3) field, data = tmp
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()
# Apply a smoothness constraint to the borders of the equivalent layer windows # to avoid gaps in the physical property distribution solver = misfit + 1e-18 * PELSmoothness(layer, windows, degree) solver.fit() # Add the estimated density distribution to the layer object for plotting and # forward modeling layer.addprop('density', solver.estimate_) residuals = solver[0].residuals() print("Residuals:") print("mean:", residuals.mean()) print("stddev:", residuals.std()) # Now I can forward model the layer at a greater height and check against the # true solution of the prism gz_true = prism.gz(x, y, z - 500, model) gz_up = sphere.gz(x, y, z - 500, layer) mpl.figure(figsize=(14, 4)) mpl.subplot(1, 3, 1) mpl.axis('scaled') mpl.title('Layer (kg.m^-3)') mpl.pcolor(layer.y, layer.x, layer.props['density'], layer.shape) mpl.colorbar() mpl.m2km() mpl.subplot(1, 3, 2) mpl.axis('scaled') mpl.title('Fit (mGal)') levels = mpl.contour(y, x, gz, shape, 15, color='r') mpl.contour(y, x, solver[0].predicted(), shape, levels, color='k') mpl.m2km() mpl.subplot(1, 3, 3)
""" GravMag: Forward modeling of the gravity anomaly and gravity gradient tensor using model """ from fatiando import mesher, gridder from fatiando.gravmag import sphere from fatiando.vis import mpl model = [mesher.Sphere(0, 0, 2000, 1000, {'density': 1000})] area = (-5000, 5000, -5000, 5000) shape = (100, 100) x, y, z = gridder.regular(area, shape, z=-100) gz = sphere.gz(x, y, z, model) tensor = [sphere.gxx(x, y, z, model), sphere.gxy(x, y, z, model), sphere.gxz(x, y, z, model), sphere.gyy(x, y, z, model), sphere.gyz(x, y, z, model), sphere.gzz(x, y, z, model)] mpl.figure() mpl.axis('scaled') mpl.title('gz') mpl.contourf(y, x, gz, shape, 15) mpl.colorbar() mpl.m2km() mpl.figure() titles = ['gxx', 'gxy', 'gxz', 'gyy', 'gyz', 'gzz'] for i, field in enumerate(tensor): mpl.subplot(2, 3, i + 1) mpl.axis('scaled') mpl.title(titles[i])
# Estimate the density using enough damping so that won't try to fit the error eql = EQLGravity(x, y, z, gz, layer) + 1e-22*Damping(layer.size) eql.fit() # Now we add the estimated densities to our layer layer.addprop('density', eql.estimate_) # and print some statistics of how well the estimated layer fits the data residuals = eql[0].residuals() print("Residuals:") print(" mean:", residuals.mean(), 'mGal') print(" stddev:", residuals.std(), 'mGal') # Now I can forward model gravity data anywhere we want. For interpolation, we # calculate it on a grid. For upward continuation, at a greater height. We can # even combine both into a single operation. x2, y2, z2 = gridder.regular(area, (50, 50), z=-1000) gz_up = sphere.gz(x2, y2, z2, layer) fig, axes = plt.subplots(1, 2, figsize=(8, 6)) ax = axes[0] ax.set_title('Original data') ax.set_aspect('equal') tmp = ax.tricontourf(y/1000, x/1000, gz, 30, cmap='viridis') fig.colorbar(tmp, ax=ax, pad=0.1, aspect=30, orientation='horizontal').set_label('mGal') ax.plot(y/1000, x/1000, 'xk') ax.set_xlabel('y (km)') ax.set_ylabel('x (km)') ax = axes[1]