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_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_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 plot_data(coordinates, velocity, weights, title_data, title_weights): "Make two maps of our data, one with the data and one with the weights/uncertainty" fig, axes = plt.subplots(1, 2, figsize=(9.5, 7), subplot_kw=dict(projection=ccrs.Mercator())) crs = ccrs.PlateCarree() ax = axes[0] ax.set_title(title_data) maxabs = vd.maxabs(velocity) pc = ax.scatter( *coordinates, c=velocity, s=30, cmap="seismic", vmin=-maxabs, vmax=maxabs, transform=crs, ) plt.colorbar(pc, ax=ax, orientation="horizontal", pad=0.05).set_label("m/yr") vd.datasets.setup_california_gps_map(ax) ax = axes[1] ax.set_title(title_weights) pc = ax.scatter(*coordinates, c=weights, s=30, cmap="magma", transform=crs, norm=LogNorm()) plt.colorbar(pc, ax=ax, orientation="horizontal", pad=0.05) vd.datasets.setup_california_gps_map(ax) plt.show()
def test_gradient_boosted_eqs_float32(coordinates, data): """ Check that predictions are reasonable when interpolating from one grid to a denser grid, using float32 as dtype. """ eqs = EquivalentSourcesGB(depth=500, damping=None, window_size=1e3, random_state=42, dtype="float32") eqs.fit(coordinates, data) # Error tolerance is 5% of the maximum data. npt.assert_allclose(data, eqs.predict(coordinates), rtol=0, atol=0.05 * vd.maxabs(data))
def test_gb_eqs_small_data(coordinates_small, data_small, weights): """ Check predictions against synthetic data using few data points for speed """ # The interpolation should be good enought on the data points # Gradient-boosted equivalent sources don't perform well on small data, so # we will check if the error is no larger than 1mGal # (sample data ranges from approximately -7mGal to 7mGal) eqs = EquivalentSourcesGB(depth=1e3, damping=None, window_size=1e3, random_state=42) eqs.fit(coordinates_small, data_small, weights=weights) # Error tolerance is 5% of the maximum data. npt.assert_allclose( data_small, eqs.predict(coordinates_small), rtol=0, atol=0.05 * vd.maxabs(data_small), )
def plot_data(column, i, title): "Plot the column from the DataFrame in the ith subplot" crs = ccrs.PlateCarree() ax = plt.subplot(2, 2, i, projection=ccrs.Mercator()) ax.set_title(title) # Set vmin and vmax to the extremes of the original data maxabs = vd.maxabs(data.air_temperature_c) mappable = ax.scatter( data.longitude, data.latitude, c=data[column], s=50, cmap="seismic", vmin=-maxabs, vmax=maxabs, transform=crs, ) # Set the proper ticks for a Cartopy map vd.datasets.setup_texas_wind_map(ax) return mappable
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)
reference=0, properties={"density": density}, ) # Compute gravity field on a regular grid located at 4000m above the ellipsoid coordinates = vd.grid_coordinates(region=(12, 33, -35, -18), spacing=0.2, extra_coords=4000) easting, northing = projection(*coordinates[:2]) coordinates_projected = (easting, northing, coordinates[-1]) prisms_gravity = prisms.prism_layer.gravity(coordinates_projected, field="g_z") # Make a plot of the computed gravity plt.figure(figsize=(8, 8)) ax = plt.axes(projection=ccrs.Mercator()) maxabs = vd.maxabs(prisms_gravity) tmp = ax.pcolormesh(*coordinates[:2], prisms_gravity, vmin=-maxabs, vmax=maxabs, cmap="RdBu_r", transform=ccrs.PlateCarree()) ax.set_extent(vd.get_region(coordinates), crs=ccrs.PlateCarree()) plt.title("Gravitational acceleration of the topography") plt.colorbar(tmp, label="mGal", orientation="horizontal", shrink=0.93, pad=0.01, aspect=50) plt.show()
ax = axes[0] ax.set_title("Trend") tmp = ax.scatter( data.longitude, data.latitude, c=trend_values, s=60, cmap="plasma", transform=ccrs.PlateCarree(), ) plt.colorbar(tmp, ax=ax, orientation="horizontal", pad=0.06) vd.datasets.setup_texas_wind_map(ax) ax = axes[1] ax.set_title("Residuals") maxabs = vd.maxabs(residuals) tmp = ax.scatter( data.longitude, data.latitude, c=residuals, s=60, cmap="bwr", vmin=-maxabs, vmax=maxabs, transform=ccrs.PlateCarree(), ) plt.colorbar(tmp, ax=ax, orientation="horizontal", pad=0.08) vd.datasets.setup_texas_wind_map(ax) plt.show() ########################################################################################
print("\nGridded 2-component trend:") print(grid) # Now we can map both trends along with the original data for comparison fig, axes = plt.subplots(1, 2, figsize=(9, 7), subplot_kw=dict(projection=ccrs.Mercator())) crs = ccrs.PlateCarree() # Plot the two trend components titles = ["East component trend", "North component trend"] components = [grid.east_component, grid.north_component] for ax, component, title in zip(axes, components, titles): ax.set_title(title) # Plot the trend in pseudo color maxabs = vd.maxabs(component) tmp = ax.pcolormesh( component.longitude, component.latitude, component.values, vmin=-maxabs, vmax=maxabs, cmap="seismic", transform=crs, ) cb = plt.colorbar(tmp, ax=ax, orientation="horizontal", pad=0.05) cb.set_label("meters/year") # Plot the original data ax.quiver( data.longitude.values, data.latitude.values,
grid = eqs.grid( upward=coordinates[-1].max(), spacing=0.2, data_names=["gravity_disturbance"], ) # The grid is a xarray.Dataset with values, coordinates, and metadata print("\nGenerated grid:\n", grid) # Mask grid points too far from data points grid = vd.distance_mask(data_coordinates=coordinates, maxdist=0.5, grid=grid) # Get the maximum absolute value between the original and gridded data so we # can use the same color scale for both plots and have 0 centered at the white # color. maxabs = vd.maxabs(gravity_disturbance, grid.gravity_disturbance.values) # Get the region boundaries region = vd.get_region(coordinates) # Plot observed and gridded gravity disturbance fig, (ax1, ax2) = plt.subplots( nrows=1, ncols=2, figsize=(10, 5), sharey=True, ) tmp = ax1.scatter( longitude, latitude,
print("R² score:", eql.score(coordinates, data.total_field_anomaly_nt)) # Interpolate data on a regular grid with 400 m spacing. The interpolation requires an # extra coordinate (upward height). By passing in 500 m, we're effectively # upward-continuing the data (mean flight height is 200 m). grid = eql.grid(spacing=400, data_names=["magnetic_anomaly"], extra_coords=500) # The grid is a xarray.Dataset with values, coordinates, and metadata print("\nGenerated grid:\n", grid) # Plot original magnetic anomaly and the gridded and upward-continued version fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(12, 6), sharey=True) # Get the maximum absolute value between the original and gridded data so we can use the # same color scale for both plots and have 0 centered at the white color. maxabs = vd.maxabs(data.total_field_anomaly_nt, grid.magnetic_anomaly.values) ax1.set_title("Observed magnetic anomaly data") tmp = ax1.scatter( easting, northing, c=data.total_field_anomaly_nt, s=20, vmin=-maxabs, vmax=maxabs, cmap="seismic", ) plt.colorbar(tmp, ax=ax1, label="nT", pad=0.05,
ax.set_aspect("equal") ax.set_yticks([]) ax.set_xticks([]) clb = plt.colorbar(tmp, ax=ax, **cbar_kwargs) clb.set_label(**cbar_label_kwargs) plt.tight_layout() plt.savefig("airborne_survey.svg") plt.show() # + ground_difference = target - ground_prediction airborne_difference = target - airborne_prediction vmin = min(ground_prediction.min(), airborne_prediction.min()) vmax = max(ground_prediction.max(), airborne_prediction.max()) difference_maxabs = vd.maxabs(ground_difference, airborne_difference) # + fig, ax = plt.subplots(figsize=figsize) tmp = plt.pcolormesh( ground_prediction.easting, ground_prediction.northing, ground_prediction.values, vmin=vmin, vmax=vmax, rasterized=True, ) ax.set_aspect("equal") ax.set_yticks([]) ax.set_xticks([]) clb = plt.colorbar(tmp, ax=ax, **cbar_kwargs)
import numpy as np import verde as vd # The data are in a pandas.DataFrame data = vd.datasets.fetch_rio_magnetic() print(data.head()) # Make a Mercator map of the data using Cartopy crs = ccrs.PlateCarree() plt.figure(figsize=(7, 5)) ax = plt.axes(projection=ccrs.Mercator()) ax.set_title("Total-field Magnetic Anomaly of Rio de Janeiro") # Since the data is diverging (going from negative to positive) we need to center our # colorbar on 0. To do this, we calculate the maximum absolute value of the data to set # vmin and vmax. maxabs = vd.maxabs(data.total_field_anomaly_nt) # Cartopy requires setting the projection of the original data through the transform # argument. Use PlateCarree for geographic data. plt.scatter( data.longitude, data.latitude, c=data.total_field_anomaly_nt, s=1, cmap="seismic", vmin=-maxabs, vmax=maxabs, transform=crs, ) plt.colorbar(pad=0.01).set_label("nT") # Set the proper ticks for a Cartopy map vd.datasets.setup_rio_magnetic_map(ax)
# the smaller values pc = ax.scatter( *coordinates, c=data.std_up * 1000, s=20, cmap="magma", transform=crs, norm=PowerNorm(gamma=1 / 2) ) cb = plt.colorbar(pc, ax=ax, orientation="horizontal", pad=0.05) cb.set_label("uncertainty [mm/yr]") vd.datasets.setup_california_gps_map(ax, region=region) # Plot the gridded velocities ax = axes[1] ax.set_title("Weighted spline interpolated velocity") maxabs = vd.maxabs(data.velocity_up) * 1000 pc = (grid.velocity * 1000).plot.pcolormesh( ax=ax, cmap="seismic", vmin=-maxabs, vmax=maxabs, transform=crs, add_colorbar=False, add_labels=False, ) cb = plt.colorbar(pc, ax=ax, orientation="horizontal", pad=0.05) cb.set_label("vertical velocity [mm/yr]") ax.scatter(*coordinates, c="black", s=0.5, alpha=0.1, transform=crs) vd.datasets.setup_california_gps_map(ax, region=region) ax.coastlines() plt.tight_layout()
# 1000 m, we're effectively upward-continuing the data. grid = eqs_gb.grid( upward=1000, spacing=2e3, data_names="gravity_disturbance", ) print(grid) # Plot the original gravity disturbance and the gridded and upward-continued # version fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(12, 9), sharey=True) # Get the maximum absolute value between the original and gridded data so we # can use the same color scale for both plots and have 0 centered at the white # color. maxabs = vd.maxabs(data.gravity_disturbance, grid.gravity_disturbance) ax1.set_title("Observed gravity disturbance data") tmp = ax1.scatter( easting, northing, c=data.gravity_disturbance, s=5, vmin=-maxabs, vmax=maxabs, cmap="seismic", ) plt.colorbar(tmp, ax=ax1, label="mGal", pad=0.07,
# 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)") # Convert axes units to km ax.set_xticklabels(ax.get_xticks() * 1e-3) ax.set_yticklabels(ax.get_yticks() * 1e-3) ax.set_xlabel("km") ax.set_ylabel("km") plt.tight_layout() plt.show()
grid = chain.grid( region=region, spacing=spacing, projection=projection, dims=["latitude", "longitude"], data_names=["total_field_anomaly"], ) print("\nChained geographic grid:") print(grid) # We'll plot only the chained grid on a Mercator map plt.figure(figsize=(7, 5)) crs = ccrs.PlateCarree() ax = plt.axes(projection=ccrs.Mercator()) ax.set_title("De-trend, decimate, and spline") maxabs = vd.maxabs(grid.total_field_anomaly) pc = ax.pcolormesh( grid.longitude, grid.latitude, grid.total_field_anomaly, transform=crs, cmap="seismic", vmin=-maxabs, vmax=maxabs, ) plt.colorbar(pc, pad=0.01).set_label("total field anomaly [nT]") # Set the proper ticks for a Cartopy map vd.datasets.setup_rio_magnetic_map(ax) plt.tight_layout() plt.show()