def test_eql_harmonic_small_data_cartesian(): """ Check predictions against synthetic data using few data points for speed Use Cartesian coordinates. """ region = (-3e3, -1e3, 5e3, 7e3) # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=-1e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(20, 20), extra_coords=0) # Get synthetic data data = point_mass_gravity(coordinates, points, masses, field="g_z") # The interpolation should be perfect on the data points eql = EQLHarmonic(relative_depth=500) eql.fit(coordinates, data) npt.assert_allclose(data, eql.predict(coordinates), rtol=1e-5) # Check that the proper source locations were set tmp = [i.ravel() for i in coordinates] npt.assert_allclose(tmp[:2], eql.points_[:2], rtol=1e-5) npt.assert_allclose(tmp[2] - 500, eql.points_[2], rtol=1e-5) # Gridding at higher altitude should be reasonably accurate when compared # to synthetic values grid = vd.grid_coordinates(region=region, shape=(20, 20), extra_coords=20) true = point_mass_gravity(grid, points, masses, field="g_z") npt.assert_allclose(true, eql.predict(grid), rtol=0.05)
def test_eql_harmonic_cartesian_parallel(): """ Check predictions when parallel is enabled and disabled """ region = (-3e3, -1e3, 5e3, 7e3) # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=-1e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(40, 40), extra_coords=0) # Get synthetic data data = point_mass_gravity(coordinates, points, masses, field="g_z") # The predictions should be equal whether are run in parallel or in serial eql_serial = EQLHarmonic(parallel=False) eql_serial.fit(coordinates, data) eql_parallel = EQLHarmonic(parallel=True) eql_parallel.fit(coordinates, data) upward = 0 shape = (60, 60) grid_serial = eql_serial.grid(upward, shape=shape, region=region) grid_parallel = eql_parallel.grid(upward, shape=shape, region=region) npt.assert_allclose(grid_serial.scalars, grid_parallel.scalars, rtol=1e-7)
def test_eql_harmonic_custom_points_cartesian(): """ Check that passing in custom points works and actually uses the points Use Cartesian coordinates. """ region = (-3e3, -1e3, 5e3, 7e3) # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=-1e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(20, 20), extra_coords=0) # Get synthetic data data = point_mass_gravity(coordinates, points, masses, field="g_z") # The interpolation should be perfect on the data points src_points = tuple( i.ravel() for i in vd.grid_coordinates(region=region, shape=(20, 20), extra_coords=-550) ) eql = EQLHarmonic(points=src_points) eql.fit(coordinates, data) npt.assert_allclose(data, eql.predict(coordinates), rtol=1e-5) # Check that the proper source locations were set npt.assert_allclose(src_points, eql.points_, rtol=1e-5) # Gridding at higher altitude should be reasonably accurate when compared # to synthetic values grid = vd.grid_coordinates(region=region, shape=(20, 20), extra_coords=20) true = point_mass_gravity(grid, points, masses, field="g_z") npt.assert_allclose(true, eql.predict(grid), rtol=0.05)
def test_same_windows_data_and_sources(): """ Check if it creates the same windows for data and sources """ spacing = 1 # Create data points on a large region region = (1, 3, 1, 3) coordinates = vd.grid_coordinates(region=region, spacing=spacing, extra_coords=0) # Create source points on a subregion sources_region = (1, 2, 1, 3) points = vd.grid_coordinates(region=sources_region, spacing=spacing, extra_coords=-10) # Create EQLHarmonicBoost # I use no shuffle so I can compare the windows with expected values eql = EQLHarmonicBoost(window_size=spacing, shuffle=False) # Make EQL believe that it has already created the points eql.points_ = points # Create windows for data points and sources source_windows, data_windows = eql._create_rolling_windows(coordinates) # Check number of windows assert len(source_windows) == 9 assert len(data_windows) == 9 # Define expected number of points inside each window for data and sources expected_data_windows = np.array([[4, 2, 4], [2, 1, 2], [4, 2, 4]]).ravel() expected_source_windows = np.array([[4, 2, 2], [2, 1, 1], [4, 2, 2]]).ravel() # Check if the windows were created correctly for i, window in enumerate(data_windows): assert len(window) == expected_data_windows[i] for i, window in enumerate(source_windows): assert len(window) == expected_source_windows[i]
def test_eql_boost_large_region(): """ Check if EQLHarmonicBoost works on a large region The iterative process ignores the effect of sources on far observation points. If the region is very large, this error should be diminished. """ # Define a squared region region = (-1000e3, 1000e3, -1000e3, 1000e3) # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=-1e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(40, 40), extra_coords=0) # Get synthetic data data = hm.point_mass_gravity(coordinates, points, masses, field="g_z") # The interpolation should be sufficiently accurate on the data points eql = EQLHarmonicBoost(window_size=100e3) eql.fit(coordinates, data) assert mean_squared_error( data, eql.predict(coordinates)) < 1e-5 * vd.maxabs(data) # Gridding onto a denser grid should be reasonably accurate when compared # to synthetic values grid = vd.grid_coordinates(region=region, shape=(60, 60), extra_coords=0) true = hm.point_mass_gravity(grid, points, masses, field="g_z") assert mean_squared_error(true, eql.predict(grid)) < 1e-3 * vd.maxabs(data)
def test_eql_boost_random_state(): """ Check if EQLHarmonicBoost produces same result by setting random_state """ region = (-3e3, -1e3, 5e3, 7e3) # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=-1e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(20, 20), extra_coords=0) # Get synthetic data data = hm.point_mass_gravity(coordinates, points, masses, field="g_z") # Initialize two EQLHarmonicBoost with the same random_state eql_a = EQLHarmonicBoost(window_size=500, random_state=0) eql_a.fit(coordinates, data) eql_b = EQLHarmonicBoost(window_size=500, random_state=0) eql_b.fit(coordinates, data) # Check if fitted coefficients are the same npt.assert_allclose(eql_a.coefs_, eql_b.coefs_)
def test_eql_harmonic_spherical(): """ Check that predictions are reasonable when interpolating from one grid to a denser grid. Use spherical coordiantes. """ region = (-70, -60, -40, -30) radius = 6400e3 # Build synthetic point masses points = vd.grid_coordinates( region=region, shape=(6, 6), extra_coords=radius - 500e3 ) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates( region=region, shape=(40, 40), extra_coords=radius ) # Get synthetic data data = point_mass_gravity( coordinates, points, masses, field="g_z", coordinate_system="spherical" ) # The interpolation should be perfect on the data points eql = EQLHarmonicSpherical(relative_depth=500e3) eql.fit(coordinates, data) npt.assert_allclose(data, eql.predict(coordinates), rtol=1e-5) # Gridding onto a denser grid should be reasonably accurate when compared # to synthetic values grid = vd.grid_coordinates(region=region, shape=(60, 60), extra_coords=radius) true = point_mass_gravity( grid, points, masses, field="g_z", coordinate_system="spherical" ) npt.assert_allclose(true, eql.predict(grid), rtol=1e-3)
def test_eql_boost_warm_start(): """ Check if EQLHarmonicBoost can be fitted with warm_start """ region = (-3e3, -1e3, 5e3, 7e3) # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=-1e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(20, 20), extra_coords=0) # Get synthetic data data = hm.point_mass_gravity(coordinates, points, masses, field="g_z") # Check if refitting with warm_start=True changes its coefficients eql = EQLHarmonicBoost(window_size=500, warm_start=True) eql.fit(coordinates, data) coefs = eql.coefs_.copy() eql.fit(coordinates, data) assert not np.allclose(coefs, eql.coefs_) # Check if refitting with warm_start=False doesn't change its coefficients # (need to set random_state, otherwise coefficients might be different due # to another random shuffling of the windows). eql = EQLHarmonicBoost(window_size=500, warm_start=False, random_state=0) eql.fit(coordinates, data) coefs = eql.coefs_.copy() eql.fit(coordinates, data) npt.assert_allclose(coefs, eql.coefs_)
def test_eql_boost_single_window(): """ Check if EQLHarmonicBoost works with a single window that covers the whole region """ # Define a squared region region = (-3e3, -1e3, 5e3, 7e3) # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=-1e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(40, 40), extra_coords=0) # Get synthetic data data = hm.point_mass_gravity(coordinates, points, masses, field="g_z") # The interpolation should be perfect on the data points eql = EQLHarmonicBoost(window_size=region[1] - region[0]) eql.fit(coordinates, data) npt.assert_allclose(data, eql.predict(coordinates), rtol=1e-5) # Gridding onto a denser grid should be reasonably accurate when compared # to synthetic values grid = vd.grid_coordinates(region=region, shape=(60, 60), extra_coords=0) true = hm.point_mass_gravity(grid, points, masses, field="g_z") npt.assert_allclose(true, eql.predict(grid), rtol=1e-3)
def test_same_windows_data_and_sources(): """ Test if _create_windows generates the same windows for data and sources """ spacing = 1 # Create data points on a large region region = (1, 3, 1, 3) coordinates = vd.grid_coordinates(region=region, spacing=spacing, extra_coords=0) # Create source points on a subregion sources_region = (1, 2, 1, 3) points = vd.grid_coordinates(region=sources_region, spacing=spacing, extra_coords=-10) # Create EquivalentSourcesGB eqs = EquivalentSourcesGB(window_size=spacing) # Make EQL believe that it has already created the points eqs.points_ = points # Create windows for data points and sources # Set suffhle to False so we can compare the windows with expected values source_windows, data_windows = eqs._create_windows(coordinates, shuffle=False) # Check number of windows assert len(source_windows) == 9 assert len(data_windows) == 9 # Define expected number of points inside each window for data and sources expected_data_windows = np.array([[4, 2, 4], [2, 1, 2], [4, 2, 4]]).ravel() expected_source_windows = np.array([[4, 2, 2], [2, 1, 1], [4, 2, 2]]).ravel() # Check if the windows were created correctly for i, window in enumerate(data_windows): assert len(window) == expected_data_windows[i] for i, window in enumerate(source_windows): assert len(window) == expected_source_windows[i]
def test_eql_harmonic_custom_points_spherical(): """ Check that passing in custom points works and actually uses the points Use spherical coordinates. """ region = (-70, -60, -40, -30) radius = 6400e3 # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=radius - 500e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(5, 5), extra_coords=radius) # Get synthetic data data = point_mass_gravity(coordinates, points, masses, field="g_z", coordinate_system="spherical") # Pass a custom set of point sources points_custom = tuple(i.ravel() for i in vd.grid_coordinates( region=region, shape=(3, 3), extra_coords=radius - 500e3)) eql = EQLHarmonicSpherical(points=points_custom) eql.fit(coordinates, data) # Check that the proper source locations were set npt.assert_allclose(points_custom, eql.points_, rtol=1e-5)
def test_eql_harmonic_custom_points_cartesian(): """ Check that passing in custom points works and actually uses the points Use Cartesian coordinates. """ region = (-3e3, -1e3, 5e3, 7e3) # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=-1e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(5, 5), extra_coords=0) # Get synthetic data data = point_mass_gravity(coordinates, points, masses, field="g_z") # Pass a custom set of point sources points_custom = tuple(i.ravel() for i in vd.grid_coordinates( region=region, shape=(3, 3), extra_coords=-550)) eql = EQLHarmonic(points=points_custom) eql.fit(coordinates, data) # Check that the proper source locations were set npt.assert_allclose(points_custom, eql.points_, rtol=1e-5)
def test_get_region_data_sources(data_region, sources_region, expected_region): """ Test the EquivalentSourcesGB._get_region_data_sources method """ shape = (8, 10) coordinates = vd.grid_coordinates(data_region, shape=shape) points = vd.grid_coordinates(sources_region, shape=shape) region = _get_region_data_sources(coordinates, points) npt.assert_allclose(region, expected_region)
def test_eql_harmonic_small_data_spherical(): """ Check predictions against synthetic data using few data points for speed Use spherical coordinates. """ region = (-70, -60, -40, -30) radius = 6400e3 # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=radius - 500e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(8, 8), extra_coords=radius) # Get synthetic data data = point_mass_gravity(coordinates, points, masses, field="g_z", coordinate_system="spherical") # The interpolation should be perfect on the data points eql = EQLHarmonicSpherical(relative_depth=500e3) eql.fit(coordinates, data) npt.assert_allclose(data, eql.predict(coordinates), rtol=1e-5) # Check that the proper source locations were set tmp = [i.ravel() for i in coordinates] npt.assert_allclose(tmp[:2], eql.points_[:2], rtol=1e-5) npt.assert_allclose(tmp[2] - 500e3, eql.points_[2], rtol=1e-5) # Gridding at higher altitude should be reasonably accurate when compared # to synthetic values upward = radius + 2e3 shape = (8, 8) grid = vd.grid_coordinates(region=region, shape=shape, extra_coords=upward) true = point_mass_gravity(grid, points, masses, field="g_z", coordinate_system="spherical") npt.assert_allclose(true, eql.predict(grid), rtol=0.05) # Test grid method grid = eql.grid(upward, shape=shape, region=region) npt.assert_allclose(true, grid.scalars, rtol=0.05)
def test_prism_layer_gravity(): """ Check if gravity method works as expected """ coordinates = vd.grid_coordinates((1, 3, 7, 10), spacing=1, extra_coords=30.0) easting = np.linspace(1, 3, 5) northing = np.linspace(7, 10, 4) shape = (northing.size, easting.size) reference = 0 surface = np.arange(20, dtype=float).reshape(shape) density = np.ones_like(surface, dtype=float) layer = prism_layer((easting, northing), surface, reference, properties={"density": density}) for field in ("potential", "g_z"): expected_result = prism_gravity( coordinates, prisms=layer.prism_layer._to_prisms(), density=density, field=field, ) npt.assert_allclose( expected_result, layer.prism_layer.gravity(coordinates, field=field))
def test_point_mass_spherical_parallel(): """ Check if parallel and serial runs return the same result """ region = (2, 10, -3, 5) radius = 6400e3 points = vd.scatter_points(region, size=30, extra_coords=radius - 10e3, random_state=0) masses = np.arange(points[0].size) coordinates = vd.grid_coordinates(region=region, spacing=1, extra_coords=radius) for field in ("potential", "g_z"): result_serial = point_gravity( coordinates, points, masses, field=field, coordinate_system="spherical", parallel=False, ) result_parallel = point_gravity( coordinates, points, masses, field=field, coordinate_system="spherical", parallel=True, ) npt.assert_allclose(result_serial, result_parallel)
def test_single_tesseroid_against_constant_density(field): """ Test the output of a single tesseroid against one with constant density """ # Define a single tesseroid with constant density bottom, top = 5400e3, 6300e3 tesseroid = [-3, 3, -2, 2, bottom, top] density = 2900.0 # Define a constant density @jit def constant_density( radius, # noqa: U100 # the radius argument is needed for the density function ): return density # Define a set of observation points coordinates = grid_coordinates(region=(-5, 5, -5, 5), spacing=1, extra_coords=top) # Compare effects against the constant density implementation npt.assert_allclose( tesseroid_gravity(coordinates, [tesseroid], density=[density], field=field), tesseroid_gravity(coordinates, [tesseroid], density=constant_density, field=field), )
def test_prisms_parallel_vs_serial(): """ Check if the parallelized run returns the same results as the serial one """ prisms = [ [-100, 0, -100, 0, -10, 0], [0, 100, -100, 0, -10, 0], [-100, 0, 0, 100, -10, 0], [0, 100, 0, 100, -10, 0], ] densities = [2000, 3000, 4000, 5000] coordinates = vd.grid_coordinates(region=(-100, 100, -100, 100), spacing=20, extra_coords=10) for field in ("potential", "g_z"): result_parallel = prism_gravity(coordinates, prisms, densities, field=field, parallel=True) result_serial = prism_gravity(coordinates, prisms, densities, field=field, parallel=False) npt.assert_allclose(result_parallel, result_serial)
def test_point_mass_cartesian_parallel(): """ Check if parallel and serial runs return the same result """ region = (2e3, 10e3, -3e3, 5e3) points = vd.scatter_points(region, size=30, extra_coords=-1e3, random_state=0) masses = np.arange(points[0].size) coordinates = vd.grid_coordinates(region=region, spacing=1e3, extra_coords=0) for field in ("potential", "g_z", "g_northing", "g_easting"): result_serial = point_gravity(coordinates, points, masses, field=field, parallel=False) result_parallel = point_gravity(coordinates, points, masses, field=field, parallel=True) npt.assert_allclose(result_serial, result_parallel)
def grid_sources(coordinates, spacing=None, depth=None, **kwargs): """ Create a regular grid of point sources All point sources will be located at the same depth, equal to the difference between the minimum elevation of observation points and the ``depth`` argument. Parameters ---------- coordinates : tuple of arrays Tuple containing the coordinates of the observation points in the following order: (``easting``, ``northing``, ``upward``). spacing : float, tuple = (s_north, s_east) The block size in the South-North and West-East directions, respectively. A single value means that the size is equal in both directions. depth : float Depth shift used to compute the constant depth at which point sources will be located. Returns ------- points : tuple of arrays Tuple containing the coordinates of the source points in the following order: (``easting``, ``northing``, ``upward``). """ # Generate grid sources region = get_region(coordinates) easting, northing = grid_coordinates(region=region, spacing=spacing) upward = np.full_like(easting, coordinates[2].min()) - depth return easting, northing, upward
def test_gradient_boosted_eqs_predictions(region, points, masses, coordinates, data): """ Test GB eq-sources predictions """ # The interpolation should be sufficiently accurate on the data points eqs = EquivalentSourcesGB(window_size=1e3, depth=1e3, damping=None, random_state=42) eqs.fit(coordinates, data) # Error tolerance is 2% of the maximum data. npt.assert_allclose(data, eqs.predict(coordinates), rtol=0, atol=0.02 * vd.maxabs(data)) # Gridding onto a denser grid should be reasonably accurate when compared # to synthetic values grid = vd.grid_coordinates(region, shape=(60, 60), extra_coords=0) true = point_gravity(grid, points, masses, field="g_z") # Error tolerance is 2% of the maximum data. npt.assert_allclose(true, eqs.predict(grid), rtol=0, atol=0.02 * vd.maxabs(true))
def test_prism_layer_gravity_density_nans(field, dummy_layer, prism_layer_with_holes): """ Check if prisms is ignored after a nan is found in density array """ coordinates = vd.grid_coordinates((1, 3, 7, 10), spacing=1, extra_coords=30.0) prisms_coords, surface, reference, density = dummy_layer # Create one layer that has nans on the density array indices = [(3, 3), (2, 1)] for index in indices: density[index] = np.nan layer = prism_layer(prisms_coords, surface, reference, properties={"density": density}) # Check if warning is raised after passing density with nans with warnings.catch_warnings(record=True) as warn: result = layer.prism_layer.gravity(coordinates, field=field) assert len(warn) == 1 # Check if it generates the expected gravity field prisms, rho = prism_layer_with_holes npt.assert_allclose( result, prism_gravity(coordinates, prisms, rho, field=field), )
def test_dtype( region, coordinates, data, weights, block_size, custom_points, weights_none, damping, dtype, ): """ Test dtype argument on EquivalentSources """ # Define the points argument for EquivalentSources points = None if custom_points: points = vd.grid_coordinates(region, spacing=300, extra_coords=-2e3) # Define the points argument for EquivalentSources.fit() if weights_none: weights = None # Initialize and fit the equivalent sources eqs = EquivalentSources( damping=damping, points=points, block_size=block_size, dtype=dtype ) eqs.fit(coordinates, data, weights) # Make some predictions prediction = eqs.predict(coordinates) # Check data type of created objects for coord in eqs.points_: assert coord.dtype == np.dtype(dtype) assert prediction.dtype == np.dtype(dtype)
def test_equivalent_sources_jacobian_cartesian(): """ Test Jacobian matrix under symmetric system of point sources. Use Cartesian coordinates. """ easting, northing, upward = vd.grid_coordinates( region=[-100, 100, -100, 100], shape=(2, 2), extra_coords=0 ) points = vdb.n_1d_arrays((easting, northing, upward + 100), n=3) coordinates = vdb.n_1d_arrays((easting, northing, upward), n=3) n_points = points[0].size jacobian = np.zeros((n_points, n_points), dtype=points[0].dtype) jacobian_numba_serial(coordinates, points, jacobian, greens_func_cartesian) # All diagonal elements must be equal diagonal = np.diag_indices(4) npt.assert_allclose(jacobian[diagonal][0], jacobian[diagonal]) # All anti-diagonal elements must be equal (elements between distant # points) anti_diagonal = (diagonal[0], diagonal[1][::-1]) npt.assert_allclose(jacobian[anti_diagonal][0], jacobian[anti_diagonal]) # All elements corresponding to nearest neighbors must be equal nearest_neighbours = np.ones((4, 4), dtype=bool) nearest_neighbours[diagonal] = False nearest_neighbours[anti_diagonal] = False npt.assert_allclose(jacobian[nearest_neighbours][0], jacobian[nearest_neighbours])
def test_equivalent_sources_points_depth(points, coordinates_small, data_small): """ Check if the points coordinates are properly defined by the fit method """ easting, northing, upward = coordinates_small[:] # Test with constant depth eqs = EquivalentSources(depth=1.3e3, depth_type="constant") eqs.fit(coordinates_small, data_small) expected_points = vdb.n_1d_arrays( (easting, northing, -1.3e3 * np.ones_like(easting)), n=3 ) npt.assert_allclose(expected_points, eqs.points_) # Test with relative depth eqs = EquivalentSources(depth=1.3e3, depth_type="relative") eqs.fit(coordinates_small, data_small) expected_points = vdb.n_1d_arrays((easting, northing, upward - 1.3e3), n=3) npt.assert_allclose(expected_points, eqs.points_) # Test with invalid depth_type eqs = EquivalentSources( depth=300, depth_type="constant" ) # init with valid depth_type eqs.depth_type = "blabla" # change depth_type afterwards points = eqs._build_points( vd.grid_coordinates(region=(-1, 1, -1, 1), spacing=0.25, extra_coords=1) ) assert points is None
def test_equivalent_sources_cartesian_float32( region, points, masses, coordinates, data ): """ Check that predictions are reasonable when interpolating from one grid to a denser grid, using float32 as dtype. """ # The interpolation should be perfect on the data points eqs = EquivalentSources(dtype="float32") eqs.fit(coordinates, data) npt.assert_allclose(data, eqs.predict(coordinates), atol=1e-3 * vd.maxabs(data)) # Gridding onto a denser grid should be reasonably accurate when compared # to synthetic values upward = 0 shape = (60, 60) grid = vd.grid_coordinates(region=region, shape=shape, extra_coords=upward) true = point_gravity(grid, points, masses, field="g_z") npt.assert_allclose(true, eqs.predict(grid), atol=1e-3 * vd.maxabs(true)) # Test grid method grid = eqs.grid(upward, shape=shape, region=region) npt.assert_allclose(true, grid.scalars, atol=1e-3 * vd.maxabs(true)) # Test profile method point1 = (region[0], region[2]) point2 = (region[0], region[3]) profile = eqs.profile(point1, point2, upward, shape[0]) true = point_gravity( (profile.easting, profile.northing, profile.upward), points, masses, field="g_z" ) npt.assert_allclose(true, profile.scalars, atol=1e-3 * vd.maxabs(true))
def test_eql_harmonic_cartesian(): """ Check that predictions are reasonable when interpolating from one grid to a denser grid. Use Cartesian coordinates. """ region = (-3e3, -1e3, 5e3, 7e3) # Build synthetic point masses points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=-1e3) masses = vd.datasets.CheckerBoard(amplitude=1e13, region=region).predict(points) # Define a set of observation points coordinates = vd.grid_coordinates(region=region, shape=(40, 40), extra_coords=0) # Get synthetic data data = point_mass_gravity(coordinates, points, masses, field="g_z") # The interpolation should be perfect on the data points eql = EQLHarmonic() eql.fit(coordinates, data) npt.assert_allclose(data, eql.predict(coordinates), rtol=1e-5) # Gridding onto a denser grid should be reasonably accurate when compared # to synthetic values upward = 0 shape = (60, 60) grid = vd.grid_coordinates(region=region, shape=shape, extra_coords=upward) true = point_mass_gravity(grid, points, masses, field="g_z") npt.assert_allclose(true, eql.predict(grid), rtol=1e-3) # Test grid method grid = eql.grid(upward, shape=shape, region=region) npt.assert_allclose(true, grid.scalars, rtol=1e-3) # Test profile method point1 = (region[0], region[2]) point2 = (region[0], region[3]) profile = eql.profile(point1, point2, upward, shape[0]) true = point_mass_gravity( (profile.easting, profile.northing, profile.upward), points, masses, field="g_z") npt.assert_allclose(true, profile.scalars, rtol=1e-3)
def fixture_points(region): """ Return the coordinates of some sample point masses """ points = vd.grid_coordinates(region=region, shape=(6, 6), extra_coords=-1e3) return points
def fixture_coordinates_9x9(region): """ Return a small set of 81 coordinates and variable elevation """ shape = (9, 9) easting, northing = vd.grid_coordinates(region, shape=shape) upward = np.arange(shape[0] * shape[1], dtype=float).reshape(shape) coordinates = (easting, northing, upward) return coordinates
def fixture_coordinates_small(region): """ Return a small set of 25 coordinates and variable elevation """ shape = (5, 5) easting, northing = vd.grid_coordinates(region=region, shape=shape) upward = np.arange(25, dtype=float).reshape(shape) coordinates = (easting, northing, upward) return coordinates