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_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_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_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_warm_start_new_coords():
    """
    Check if sources are not changed when warm_start is True

    If the gridder is already fitted (and has warm_start=True), the location of
    the sources must not be modified, even if the new fitting process is
    carried out with another set of observation points.
    """
    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")

    # Capture the location of sources created by EQLHarmonicBoost on the first fit
    eql = EQLHarmonicBoost(window_size=500, warm_start=True)
    eql.fit(coordinates, data)
    sources = tuple(c.copy() for c in eql.points_)

    # Fit the gridder with a new set of observation data
    coordinates_new = (coordinates[0] + 100, coordinates[1] - 100,
                       coordinates[2])
    data_new = hm.point_mass_gravity(coordinates_new,
                                     points,
                                     masses,
                                     field="g_z")
    eql.fit(coordinates_new, data_new)
    # Check if sources remain on the same location
    for i in range(3):
        npt.assert_allclose(sources[i], eql.points_[i])
def test_eql_boost_custom_points():
    """
    Check EQLHarmonicBoost with custom points

    Check if the iterative gridder works well with a custom set of sources.
    By default, the gridder puts one source beneath each data point, therefore
    the indices of data and sources windows are identical. When passing
    a custom set of sources, these indices may differ.
    """
    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")

    # Define a set of block-averaged equivalent sources
    sources = block_averaged_sources(coordinates,
                                     100,
                                     depth_type="relative_depth",
                                     depth=500)

    # Fit EQLHarmonicBoost with the block-averaged sources
    eql = EQLHarmonicBoost(window_size=500, points=sources)
    eql.fit(coordinates, data)

    # Check if sources are located on the same points
    for i in range(3):
        npt.assert_allclose(sources[i], eql.points_[i])

    # The interpolation should be sufficiently accurate on the data points
    assert mean_squared_error(
        data, eql.predict(coordinates)) < 1e-3 * vd.maxabs(data)
예제 #7
0
northing = [7e3, 13e3]
# The vertical coordinate is positive upward so negative numbers represent depth
upward = [-0.5e3, -1e3]
points = [easting, northing, upward]
# We're using "negative" masses to represent a "mass deficit" since we assume
# measurements are gravity disturbances, not actual gravity values.
masses = [3e11, -10e11]

# Define computation points on a grid at 500m above the ground
coordinates = vd.grid_coordinates(
    region=[0, 20e3, 0, 20e3], shape=(100, 100), extra_coords=500
)

# Compute the downward component of the gravitational acceleration
gravity = hm.point_mass_gravity(
    coordinates, points, masses, field="g_z", coordinate_system="cartesian"
)
print(gravity)

# Plot the results on a map
fig, ax = plt.subplots(figsize=(8, 6))
ax.set_aspect("equal")
# Get the maximum absolute value so we can center the colorbar on zero
maxabs = vd.maxabs(gravity)
img = ax.contourf(
    *coordinates[:2], gravity, 60, vmin=-maxabs, vmax=maxabs, cmap="seismic"
)
plt.colorbar(img, ax=ax, pad=0.04, shrink=0.73, label="mGal")
# Plot the point mass locations
ax.plot(easting, northing, "oy")
ax.set_title("Gravitational acceleration (downward)")