Ensemble 1: constraint spacing vs regional field strength

*with density estimation

This notebooks performs 100 synthetic inversions, with all combinations of 10 values of constraint (bathymetry point measurement) spacing, and 10 values of the strength (standard deviation) of the regional component of the gravity field. For each inversion, we estimate the optimal density contrast value for the seafloor with a cross-validation of the constraint points.

import packages

[1]:
%load_ext autoreload
%autoreload 2

import copy
import itertools
import logging
import os
import pathlib
import pickle
import shutil

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import scipy as sp
import verde as vd
import xarray as xr
import xrft
from invert4geom import inversion, optimization, plotting, utils
from polartoolkit import maps
from polartoolkit import utils as polar_utils
from tqdm.autonotebook import tqdm

import synthetic_bathymetry_inversion.plotting as synth_plotting
from synthetic_bathymetry_inversion import synthetic

os.environ["POLARTOOLKIT_HEMISPHERE"] = "south"

logging.getLogger().setLevel(logging.INFO)
/home/mdtanker/miniforge3/envs/synthetic_bathymetry_inversion/lib/python3.12/site-packages/UQpy/__init__.py:6: UserWarning:

pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.

[2]:
ensemble_path = "../results/Ross_Sea/ensembles/Ross_Sea_ensemble_01_constraint_spacing_vs_regional_strength_density_estimation"
ensemble_fname = f"{ensemble_path}.csv"
[3]:
# set grid parameters
spacing = 2e3
inversion_region = (-40e3, 110e3, -1600e3, -1400e3)

true_density_contrast = 1476

bathymetry, basement, original_grav_df = synthetic.load_synthetic_model(
    spacing=spacing,
    inversion_region=inversion_region,
    buffer=spacing * 10,
    basement=True,
    zref=0,
    bathymetry_density_contrast=true_density_contrast,
)
buffer_region = polar_utils.get_grid_info(bathymetry)[1]

inversion_area = (
    (inversion_region[1] - inversion_region[0])
    / 1e3
    * (inversion_region[3] - inversion_region[2])
    / 1e3
)
inside_bathymetry = bathymetry.sel(
    easting=slice(inversion_region[0], inversion_region[1]),
    northing=slice(inversion_region[2], inversion_region[3]),
)

inversion_area
requested spacing (2000.0) is smaller than the original (5000.0).
requested spacing (2000.0) is smaller than the original (5000.0).
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_4_1.png
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_4_4.png
[3]:
30000.0
[4]:
# normalize regional gravity between 0 and 1
original_grav_df["basement_grav_normalized"] = (
    vd.grid_to_table(
        utils.normalize_xarray(
            original_grav_df.set_index(["northing", "easting"])
            .to_xarray()
            .basement_grav,
            low=-1,
            high=1,
        )
    )
    .reset_index()
    .basement_grav
)
original_grav_df = original_grav_df.drop(
    columns=["basement_grav", "disturbance", "gravity_anomaly"]
)
original_grav_df
[4]:
northing easting upward bathymetry_grav basement_grav_normalized
0 -1600000.0 -40000.0 1000.0 -35.551085 -0.575645
1 -1600000.0 -38000.0 1000.0 -36.054683 -0.523223
2 -1600000.0 -36000.0 1000.0 -36.473168 -0.466365
3 -1600000.0 -34000.0 1000.0 -36.755627 -0.406022
4 -1600000.0 -32000.0 1000.0 -36.951045 -0.343163
... ... ... ... ... ...
7671 -1400000.0 102000.0 1000.0 -25.760090 0.399167
7672 -1400000.0 104000.0 1000.0 -25.911429 0.334798
7673 -1400000.0 106000.0 1000.0 -26.032814 0.268741
7674 -1400000.0 108000.0 1000.0 -26.121903 0.201716
7675 -1400000.0 110000.0 1000.0 -26.206160 0.134418

7676 rows × 5 columns

[5]:
num = 10

# Define total number of constraints
constraint_numbers = [
    round(x) for x in np.geomspace(4, 650, num)
]  # -> median distance of 17.7-2.5 km, log scale, w/ border

constraint_numbers = [round(i) for i in constraint_numbers]
assert len(pd.Series(constraint_numbers).unique()) == num

# Define regional strength
regional_strengths = [float(round(x, 2)) for x in np.linspace(20, 200, num)]

print("number of constraints:", constraint_numbers)
print("regional strengths:", regional_strengths)
number of constraints: [4, 7, 12, 22, 38, 68, 119, 210, 369, 650]
regional strengths: [20.0, 40.0, 60.0, 80.0, 100.0, 120.0, 140.0, 160.0, 180.0, 200.0]
[6]:
# turn into dataframe
sampled_params_df = pd.DataFrame(
    itertools.product(
        constraint_numbers,
        regional_strengths,
    ),
    columns=[
        "constraint_numbers",
        "regional_strengths",
    ],
)

sampled_params_dict = dict(
    constraint_numbers=dict(sampled_values=sampled_params_df.constraint_numbers),
    regional_strengths=dict(sampled_values=sampled_params_df.regional_strengths),
)

plotting.plot_latin_hypercube(
    sampled_params_dict,
)
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_7_0.png
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_7_1.png
[7]:
sampled_params_df.dtypes
[7]:
constraint_numbers      int64
regional_strengths    float64
dtype: object

Create starting models and constraints

Only need to do this for unique combinations of constraint_numbers and constraint_noise_levels

[8]:
starting_topography_kwargs = dict(
    method="splines",
    region=buffer_region,
    spacing=spacing,
    dampings=None,
)

# get high res grid for computing constraint spacing
bathymetry_highres, _, _ = synthetic.load_synthetic_model(
    spacing=500,
    just_topography=True,
)

# clip to inversion region
bathymetry_highres = bathymetry_highres.sel(
    easting=slice(inversion_region[0], inversion_region[1]),
    northing=slice(inversion_region[2], inversion_region[3]),
)
requested spacing (500.0) is smaller than the original (5000.0).
[ ]:
sampled_params_df["constraint_points_fname"] = np.nan
sampled_params_df["starting_bathymetry_fname"] = np.nan
# sampled_params_df["starting_prisms_fname"] = np.nan

for i, row in tqdm(sampled_params_df.iterrows(), total=len(sampled_params_df)):
    # check if constraint spacing is already done
    # if so, copy it
    subset_with_same_params = sampled_params_df[
        sampled_params_df.constraint_numbers == row.constraint_numbers
    ]
    if (len(subset_with_same_params) > 1) & (
        pd.notna(subset_with_same_params.constraint_points_fname.iloc[0])
    ):
        # copy and rename files
        shutil.copy(
            subset_with_same_params.constraint_points_fname.iloc[0],
            f"{ensemble_path}_constraint_points_{i}.csv",
        )
        shutil.copy(
            subset_with_same_params.starting_bathymetry_fname.iloc[0],
            f"{ensemble_path}_starting_bathymetry_{i}.nc",
        )
        # shutil.copy(
        #     subset_with_same_params.starting_prisms_fname.iloc[0],
        #     f"{ensemble_path}_starting_prisms_{i}.nc",
        # )

        # copy other columns
        sampled_params_df.loc[i, "constraints_starting_rmse"] = (
            subset_with_same_params.constraints_starting_rmse.iloc[0]
        )
        print("skipping and using already created data")
    else:
        # make constraint points
        constraint_points = synthetic.constraint_layout_number(
            num_constraints=row.constraint_numbers,
            region=inversion_region,
            padding=-spacing,
            # plot=True,
            seed=10,
            shapefile="../results/Ross_Sea/Ross_Sea_outline.shp",
            add_outside_points=True,
            grid_spacing=spacing,
        )

        # sample true topography at these points
        constraint_points = utils.sample_grids(
            constraint_points,
            bathymetry,
            "true_upward",
            coord_names=("easting", "northing"),
        )
        constraint_points["upward"] = constraint_points.true_upward

        # grid the sampled values using verde
        starting_bathymetry = utils.create_topography(
            constraints_df=constraint_points,
            **starting_topography_kwargs,
        )

        # sample the inverted topography at the constraint points
        constraint_points = utils.sample_grids(
            constraint_points,
            starting_bathymetry,
            "starting_bathymetry",
            coord_names=("easting", "northing"),
        )

        constraints_rmse = utils.rmse(
            constraint_points.true_upward - constraint_points.starting_bathymetry
        )

        zref = 0

        sampled_params_df.loc[i, "constraints_starting_rmse"] = constraints_rmse
        starting_bathymetry.attrs["damping"] = None

        # save to files
        constraint_points.to_csv(
            f"{ensemble_path}_constraint_points_{i}.csv", index=False
        )
        starting_bathymetry.drop_attrs().to_netcdf(
            f"{ensemble_path}_starting_bathymetry_{i}.nc"
        )
        # starting_prisms.to_netcdf(f"{ensemble_path}_starting_prisms_{i}.nc")

    # set file names, add to dataframe
    sampled_params_df.loc[i, "constraint_points_fname"] = (
        f"{ensemble_path}_constraint_points_{i}.csv"
    )
    sampled_params_df.loc[i, "starting_bathymetry_fname"] = (
        f"{ensemble_path}_starting_bathymetry_{i}.nc"
    )
    # sampled_params_df.loc[i, "starting_prisms_fname"] = (
    #     f"{ensemble_path}_starting_prisms_{i}.nc"
    # )


sampled_params_df
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
skipping and using already created data
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356
... ... ... ... ... ...
95 650 120.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303
96 650 140.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303
97 650 160.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303
98 650 180.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303
99 650 200.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303

100 rows × 5 columns

[10]:
for i, row in tqdm(sampled_params_df.iterrows(), total=len(sampled_params_df)):
    # load data
    constraint_points = pd.read_csv(row.constraint_points_fname)

    # calculate min dist between each grid cell and nearest constraint
    coords = vd.grid_coordinates(
        region=inversion_region,
        spacing=100,
    )
    grid = vd.make_xarray_grid(coords, np.ones_like(coords[0]), data_names="z").z
    min_dist = utils.dist_nearest_points(
        constraint_points,
        grid,
    ).min_dist

    # mask to the ice shelf outline
    min_dist = polar_utils.mask_from_shp(
        shapefile="../results/Ross_Sea/Ross_Sea_outline.shp",
        grid=min_dist,
        invert=False,
        masked=True,
    )
    # calculate average constraint spacing
    # constraint_spacing =  (
    #     np.median(
    #         vd.median_distance(
    #             (constraint_points.easting, constraint_points.northing),
    #             k_nearest=1,
    #         )
    #     )
    #     / 1e3
    # )
    constraint_proximity = int(min_dist.median().to_numpy()) / 1e3
    sampled_params_df.loc[i, "median_proximity"] = constraint_proximity
    sampled_params_df.loc[i, "maximum_constraint_proximity"] = (
        int(min_dist.max().to_numpy()) / 1e3
    )
    sampled_params_df.loc[i, "constraint_proximity_skewness"] = sp.stats.skew(
        min_dist.to_numpy().ravel(), nan_policy="omit"
    )
    sampled_params_df.loc[i, "constraints_per_10000sq_km"] = (
        len(constraint_points) / inversion_area
    ) * 10e3

sampled_params_df
[10]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667
... ... ... ... ... ... ... ... ... ...
95 650 120.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667
96 650 140.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667
97 650 160.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667
98 650 180.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667
99 650 200.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667

100 rows × 9 columns

[11]:
sampled_params_df[
    [
        "constraint_numbers",
        "median_proximity",
        "maximum_constraint_proximity",
        "constraint_proximity_skewness",
    ]
].describe()
[11]:
constraint_numbers median_proximity maximum_constraint_proximity constraint_proximity_skewness
count 100.000000 100.000000 100.000000 100.000000
mean 149.900000 8.919700 25.135300 0.259203
std 200.751844 5.092535 14.650223 0.192085
min 4.000000 2.520000 6.333000 -0.144477
25% 12.000000 4.256000 12.387000 0.146099
50% 53.000000 7.956500 20.771500 0.277189
75% 210.000000 13.483000 38.792000 0.441687
max 650.000000 17.755000 51.305000 0.483691
[12]:
ax = sampled_params_df[::num].median_proximity.plot(c="g")
ax2 = ax.twinx()
ax2 = sampled_params_df[::num].constraint_numbers.plot(ax=ax2)
ax.legend()
ax2.legend()
[12]:
<matplotlib.legend.Legend at 0x7f340c26eb10>
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_14_1.png
[13]:
ax = sampled_params_df[::num].constraint_proximity_skewness.plot(c="g")
ax2 = ax.twinx()
ax2 = sampled_params_df[::num].median_proximity.plot(ax=ax2)
ax.legend()
ax2.legend()
[13]:
<matplotlib.legend.Legend at 0x7f340c2eacc0>
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_15_1.png
[14]:
# subplots showing starting bathymetry error
grids = []
titles = []
cbar_labels = []
constraints = []
for i, row in sampled_params_df.iterrows():
    if i % num == 0:
        constraint_points = pd.read_csv(row.constraint_points_fname)

        # calculate min dist between each grid cell and nearest constraint
        coords = vd.grid_coordinates(
            region=inversion_region,
            spacing=100,
        )
        grid = vd.make_xarray_grid(coords, np.ones_like(coords[0]), data_names="z").z
        min_dist = (
            utils.dist_nearest_points(
                constraint_points,
                grid,
            ).min_dist
            / 1e3
        )

        # mask to the ice shelf outline
        min_dist = polar_utils.mask_from_shp(
            shapefile="../results/Ross_Sea/Ross_Sea_outline.shp",
            grid=min_dist,
            invert=False,
            masked=True,
        )

        # add to lists
        grids.append(min_dist)
        titles.append(f"Median: {round(row.median_proximity)}")
        # cbar_labels.append(f"RMSE: {round(utils.rmse(dif),2)} (m)")
        constraints.append(constraint_points[constraint_points.inside])

fig = maps.subplots(
    grids,
    fig_title="Constraint proximity",
    titles=titles,
    cbar_label="distance (km)",
    cmap="dense",
    hist=True,
    cpt_lims=polar_utils.get_combined_min_max(grids, robust=True),
    point_sets=constraints,
    # points_style="p.02c",
    cbar_font="18p,Helvetica,black",
    yshift_amount=-1.2,
)


fig.show()
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_16_0.png
[15]:
# subplots showing starting bathymetry error
grids = []
titles = []
cbar_labels = []
constraints = []
for i, row in sampled_params_df.iterrows():
    if i % num == 0:
        starting_bathymetry = xr.open_dataarray(row.starting_bathymetry_fname)
        constraint_points = pd.read_csv(row.constraint_points_fname)

        dif = bathymetry - starting_bathymetry

        dif = dif.sel(
            easting=slice(inversion_region[0], inversion_region[1]),
            northing=slice(inversion_region[2], inversion_region[3]),
        )
        # add to lists
        grids.append(dif)
        titles.append(f"# constraints: {round(row.constraint_numbers)}")
        cbar_labels.append(f"RMSE: {round(utils.rmse(dif), 2)} (m)")
        constraints.append(constraint_points)

fig = maps.subplots(
    grids,
    fig_title="Starting bathymetry error",
    titles=titles,
    cbar_labels=cbar_labels,
    cmap="balance+h0",
    hist=True,
    cpt_lims=polar_utils.get_combined_min_max(grids, robust=True),
    point_sets=constraints,
    # points_style="p.02c",
    cbar_font="18p,Helvetica,black",
    yshift_amount=-1.2,
)

fig.show()
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_17_0.png
[16]:
sampled_params_df.columns
[16]:
Index(['constraint_numbers', 'regional_strengths', 'constraint_points_fname',
       'starting_bathymetry_fname', 'constraints_starting_rmse',
       'median_proximity', 'maximum_constraint_proximity',
       'constraint_proximity_skewness', 'constraints_per_10000sq_km'],
      dtype='object')
[17]:
metric = "median_proximity"
grids = []
names = []
for i, row in tqdm(sampled_params_df.iterrows(), total=len(sampled_params_df)):
    if i % num == 0:
        starting_bathymetry = xr.load_dataarray(row.starting_bathymetry_fname)

        starting_bathymetry = starting_bathymetry.sel(
            easting=slice(inversion_region[0], inversion_region[1]),
            northing=slice(inversion_region[2], inversion_region[3]),
        )

        grd = inside_bathymetry - starting_bathymetry

        grids.append(grd)
        names.append(round(row[metric], 1))


raps_das = []
for i, g in enumerate(grids):
    raps_das.append(
        xrft.isotropic_power_spectrum(
            g,
            dim=["easting", "northing"],
            # detrend='constant',
            detrend="linear",
            # window=False,
            # nfactor=4,
            # spacing_tol=0.01,
            # nfactor=3,
            truncate=False,
        )
    )

fig, ax = plt.subplots(figsize=(5, 3.5))

norm = plt.Normalize(
    vmin=sampled_params_df[metric].min(),
    vmax=sampled_params_df[metric].max(),
)

max_powers = []
max_power_wavelengths = []
for i, da in enumerate(raps_das):
    ax.plot(
        (1 / da.freq_r) / 1e3,
        da,
        label=names[i],
        color=plt.cm.viridis(norm([names[i]])),
    )
    max_ind = da.idxmax()
    max_power = da.max().to_numpy()
    max_power_wavelength = 1 / (da[da == max_power].freq_r.to_numpy()[0]) / 1e3
    max_power_wavelengths.append(max_power_wavelength)
    max_powers.append(max_power)
    ax.scatter(
        x=max_power_wavelength,
        y=max_power,
        marker="*",
        edgecolor="black",
        linewidth=0.5,
        color=plt.cm.viridis(norm(names[i])),  # pylint: disable=no-member
        s=60,
        zorder=20,
    )
    print(f"Max y value at x value: {max_power_wavelength}")

# ax.set_xscale("log")
ax.set_yscale("log")

ax.legend(title=metric, loc="center left", bbox_to_anchor=(1, 0.5))

ax.set_xlabel("Wavelength (km)")
ax.set_ylabel("Power ($m^3$)")
ax.set_title("Radially averaged PSD of starting bed errors")
plt.tight_layout()

# ax.xaxis.set_major_formatter(mpl.ticker.StrMethodFormatter("{x:.1f}"))
Max y value at x value: 84.59814012867712
Max y value at x value: 84.59814012867712
Max y value at x value: 84.59814012867712
Max y value at x value: 84.59814012867712
Max y value at x value: 34.90619229494806
Max y value at x value: 34.90619229494806
Max y value at x value: 34.90619229494806
Max y value at x value: 21.25768200573872
Max y value at x value: 15.36769046614745
Max y value at x value: 11.988087785514033
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_19_2.png
[18]:
y = max_power_wavelengths
x = names

m, b = np.polyfit(
    x,
    y,
    1,
)

plt.scatter(
    x,
    y,
)

# plot y = m*x + b
plt.axline(xy1=(0, b), slope=m, label=f"$y = {m:.3f}x {b:+.3f}$")
plt.legend()
[18]:
<matplotlib.legend.Legend at 0x7f339c33b740>
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_20_1.png
[19]:
sampled_params_df["starting_bathymetry_mae"] = pd.Series()
sampled_params_df["starting_bathymetry_rmse"] = pd.Series()

for i, row in tqdm(sampled_params_df.iterrows(), total=len(sampled_params_df)):
    starting_bathymetry = xr.load_dataarray(row.starting_bathymetry_fname)

    starting_bathymetry = starting_bathymetry.sel(
        easting=slice(inversion_region[0], inversion_region[1]),
        northing=slice(inversion_region[2], inversion_region[3]),
    )

    starting_bathymetry_mae = float(
        np.mean(np.abs(inside_bathymetry - starting_bathymetry))
    )
    starting_bathymetry_rmse = utils.rmse(inside_bathymetry - starting_bathymetry)

    sampled_params_df.loc[i, "starting_bathymetry_mae"] = starting_bathymetry_mae
    sampled_params_df.loc[i, "starting_bathymetry_rmse"] = starting_bathymetry_rmse
sampled_params_df
[19]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446
... ... ... ... ... ... ... ... ... ... ... ...
95 650 120.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667 3.335341 5.928079
96 650 140.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667 3.335341 5.928079
97 650 160.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667 3.335341 5.928079
98 650 180.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667 3.335341 5.928079
99 650 200.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667 3.335341 5.928079

100 rows × 11 columns

[20]:
sampled_params_df.to_csv(ensemble_fname, index=False)
[21]:
sampled_params_df = pd.read_csv(ensemble_fname)
sampled_params_df.head()
[21]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446

Create observed gravity

  • rescale regional field

[22]:
sampled_params_df["grav_df_fname"] = pd.Series()

for i, row in tqdm(sampled_params_df.iterrows(), total=len(sampled_params_df)):
    # set file names, add to dataframe
    sampled_params_df.loc[i, "grav_df_fname"] = f"{ensemble_path}_grav_df_{i}.csv"

sampled_params_df.head()
[22]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse grav_df_fname
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
[23]:
logging.getLogger().setLevel(logging.WARNING)

grav_grid = original_grav_df.set_index(["northing", "easting"]).to_xarray()

for i, row in tqdm(sampled_params_df.iterrows(), total=len(sampled_params_df)):
    # re-scale the regional gravity
    regional_grav = utils.normalize_xarray(
        grav_grid.basement_grav_normalized,
        low=0,
        high=row.regional_strengths,
    ).rename("basement_grav")
    regional_grav -= regional_grav.mean()

    # add to new dataframe
    grav_df = copy.deepcopy(original_grav_df.drop(columns=["basement_grav_normalized"]))
    grav_df["basement_grav_scaled"] = (
        vd.grid_to_table(regional_grav).reset_index().basement_grav
    )

    # add basement and bathymetry forward gravities together to make observed gravity
    grav_df["gravity_anomaly"] = grav_df.bathymetry_grav + grav_df.basement_grav_scaled

    sampled_params_df.loc[i, "regional_stdev"] = grav_df.basement_grav_scaled.std()

    # save to files
    grav_df.to_csv(row.grav_df_fname, index=False)


sampled_params_df.head()
[23]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse grav_df_fname regional_stdev
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 4.089101
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 8.178203
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 12.267304
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 16.356405
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 20.445507
[24]:
sampled_params_df.to_csv(ensemble_fname, index=False)
[25]:
sampled_params_df = pd.read_csv(ensemble_fname)
sampled_params_df.head()
[25]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse grav_df_fname regional_stdev
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 4.089101
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 8.178203
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 12.267304
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 16.356405
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 20.445507
[26]:
sampled_params_df.describe()
[26]:
constraint_numbers regional_strengths constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse regional_stdev
count 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000
mean 149.900000 110.000000 0.083960 8.919700 25.135300 0.259203 330.933333 15.135699 26.063274 22.490057
std 200.751844 57.735027 0.095932 5.092535 14.650223 0.192085 66.431876 8.923908 14.282005 11.804219
min 4.000000 20.000000 0.003560 2.520000 6.333000 -0.144477 282.666667 3.335341 5.928079 4.089101
25% 12.000000 60.000000 0.006497 4.256000 12.387000 0.146099 285.333333 6.381553 11.358153 12.267304
50% 53.000000 110.000000 0.045115 7.956500 20.771500 0.277189 299.000000 13.749814 24.798910 22.490057
75% 210.000000 160.000000 0.131168 13.483000 38.792000 0.441687 350.000000 24.695177 41.525873 32.712811
max 650.000000 200.000000 0.283030 17.755000 51.305000 0.483691 496.666667 28.351063 46.321446 40.891013
[27]:
# subplots showing true regional gravity
grids = []
titles = []
for i, row in (
    sampled_params_df.sort_values(by=["regional_strengths"]).reset_index().iterrows()
):
    if i % num == 0:
        grav_df = pd.read_csv(row.grav_df_fname)

        grid = (
            grav_df.set_index(["northing", "easting"]).to_xarray().basement_grav_scaled
        )

        # add to lists
        grids.append(grid)
        titles.append(f"Field strength: {round(row.regional_strengths)}")

fig = maps.subplots(
    grids,
    fig_title="Regional gravity",
    titles=titles,
    hist=True,
    cpt_lims=polar_utils.get_combined_min_max(grids, robust=True),
    cbar_font="18p,Helvetica,black",
    yshift_amount=-1.2,
)

fig.show()
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_30_0.png
[28]:
# subplots showing gravity anomaly
grids = []
titles = []
for i, row in (
    sampled_params_df.sort_values(by=["regional_strengths"]).reset_index().iterrows()
):
    if i % num == 0:
        grav_df = pd.read_csv(row.grav_df_fname)

        grid = grav_df.set_index(["northing", "easting"]).to_xarray().gravity_anomaly

        # add to lists
        grids.append(grid)
        titles.append(f"Field strength: {round(row.regional_strengths)}")

fig = maps.subplots(
    grids,
    fig_title="Gravity anomaly",
    titles=titles,
    hist=True,
    cpt_lims=polar_utils.get_combined_min_max(grids, robust=True),
    cbar_font="18p,Helvetica,black",
    yshift_amount=-1.2,
)

fig.show()
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_31_0.png

Density optimization

[29]:
for i, row in sampled_params_df.iterrows():
    # add results file name
    sampled_params_df.loc[i, "results_fname"] = f"{ensemble_path}_results_{i}"
    sampled_params_df.loc[i, "inverted_bathymetry_fname"] = (
        f"{ensemble_path}_inverted_bathymetry_{i}.nc"
    )

sampled_params_df.head()
[29]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse grav_df_fname regional_stdev results_fname inverted_bathymetry_fname
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 4.089101 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 8.178203 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 12.267304 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 16.356405 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 20.445507 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
[30]:
for i, row in tqdm(
    # sampled_params_df.iloc[11:].iterrows(), total=len(sampled_params_df)
    sampled_params_df.iterrows(),
    total=len(sampled_params_df),
):
    # load data
    grav_df = pd.read_csv(row.grav_df_fname)
    starting_bathymetry = xr.load_dataarray(row.starting_bathymetry_fname)
    constraint_points = pd.read_csv(row.constraint_points_fname)

    # set kwargs to pass to the inversion
    kwargs = {
        # set stopping criteria
        "max_iterations": 200,
        "l2_norm_tolerance": 0.2**0.5,  # square root of the gravity noise
        "delta_l2_norm_tolerance": 1.008,
        "solver_damping": 0.025,
    }

    # run an optimization to find the optimal density contrast
    # automatically reruns inversion with optimal density contrast
    # and saves the results to <fname>_results.pickle
    _, _ = optimization.optimize_inversion_zref_density_contrast(
        grav_df=grav_df,
        constraints_df=constraint_points,
        density_contrast_limits=(1400, 3300),
        zref=0,
        n_trials=8,
        starting_topography=starting_bathymetry,
        regional_grav_kwargs=dict(
            method="constant",
            constant=0,
        ),
        fname=row.results_fname,
        plot_cv=False,
        progressbar=False,
        **kwargs,
    )

sampled_params_df.head()
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
Best density_contrast value (3300) is at the limit of provided values (3300, 1400) and thus is likely not a global minimum, expand the range of values tested to ensure the best parameter value is found.
[30]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse grav_df_fname regional_stdev results_fname inverted_bathymetry_fname
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 4.089101 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 8.178203 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 12.267304 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 16.356405 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 20.445507 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
[31]:
for i, row in sampled_params_df.iterrows():
    # load data
    grav_df = pd.read_csv(row.grav_df_fname)
    starting_bathymetry = xr.load_dataarray(row.starting_bathymetry_fname)
    constraint_points = pd.read_csv(row.constraint_points_fname)

    # load study
    with pathlib.Path(f"{row.results_fname}_study.pickle").open("rb") as f:
        study = pickle.load(f)

    # add best density to dataframe
    sampled_params_df.loc[i, "best_density_contrast"] = study.best_params[
        "density_contrast"
    ]

    # load saved inversion results
    with pathlib.Path(f"{row.results_fname}_results.pickle").open("rb") as f:
        topo_results, grav_results, parameters, elapsed_time = pickle.load(f)

    final_bathymetry = topo_results.set_index(["northing", "easting"]).to_xarray().topo

    # sample the inverted topography at the constraint points
    constraint_points = utils.sample_grids(
        constraint_points,
        final_bathymetry,
        f"inverted_bathymetry_{i}",
        coord_names=("easting", "northing"),
    )
    constraints_rmse = utils.rmse(
        constraint_points.true_upward - constraint_points[f"inverted_bathymetry_{i}"]
    )

    # clip to inversion region
    final_bathymetry = final_bathymetry.sel(
        easting=slice(inversion_region[0], inversion_region[1]),
        northing=slice(inversion_region[2], inversion_region[3]),
    )

    inversion_rmse = utils.rmse(inside_bathymetry - final_bathymetry)

    # save final topography to file
    final_bathymetry.to_netcdf(row.inverted_bathymetry_fname)

    # add to dataframe
    sampled_params_df.loc[i, "constraints_rmse"] = constraints_rmse
    sampled_params_df.loc[i, "inversion_rmse"] = inversion_rmse

sampled_params_df.head()
[31]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse grav_df_fname regional_stdev results_fname inverted_bathymetry_fname best_density_contrast constraints_rmse inversion_rmse
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 4.089101 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1516.0 100.607651 72.304561
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 8.178203 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1675.0 196.916741 145.160338
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 12.267304 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1845.0 284.907328 209.025044
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 16.356405 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2149.0 352.124626 267.289107
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 20.445507 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2538.0 405.236779 316.810444
[32]:
sampled_params_df["topo_improvement_rmse"] = (
    sampled_params_df.starting_bathymetry_rmse - sampled_params_df.inversion_rmse
)
[33]:
norm = plt.Normalize(
    vmin=sampled_params_df.regional_stdev.to_numpy().min(),
    vmax=sampled_params_df.regional_stdev.to_numpy().max(),
)

fig, ax = plt.subplots()

for i, row in sampled_params_df.iterrows():
    # load study
    with pathlib.Path(f"{row.results_fname}_study.pickle").open("rb") as f:
        study = pickle.load(f)

    label = "Best" if i == 0 else None

    study_df = study.trials_dataframe()[["value", "params_density_contrast"]]
    df = study_df.sort_values(by="params_density_contrast")
    best_score = df.value.argmin()

    ax.plot(
        df.params_density_contrast.iloc[best_score],
        df.value.iloc[best_score],
        "s",
        markersize=6,
        color="r",
        label=label,
        zorder=10,
        markeredgecolor="black",
        linewidth=0.5,
    )
    ax.plot(
        df.params_density_contrast,
        df.value,
        # marker="o",
        color=plt.cm.viridis(norm(row.regional_stdev)),  # pylint: disable=no-member
    )
    # ax.scatter(
    #     df.params_density_contrast,
    #     df.value,
    #     s=50,
    #     marker=".",
    #     color="black",
    #     edgecolors="black",
    #     zorder=10,
    # )

ax.vlines(
    true_density_contrast,
    ax.get_ylim()[0],
    ax.get_ylim()[1],
    color="black",
    linestyle="--",
    label="True",
)
ax.legend(loc="best")
ax.set_title("Density contrast optimization")
ax.set_xlabel("Density contrast (kg/m$^3$)")
ax.set_ylabel("RMSE (m)")

sm = plt.cm.ScalarMappable(cmap="viridis", norm=norm)
cax = fig.add_axes([0.93, 0.1, 0.05, 0.8])
cbar = plt.colorbar(sm, cax=cax)
cbar.set_label("Regional strength (mGal)")
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_37_0.png
[34]:
sampled_params_df.to_csv(ensemble_fname, index=False)
[35]:
sampled_params_df = pd.read_csv(ensemble_fname)
sampled_params_df.head()
[35]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse grav_df_fname regional_stdev results_fname inverted_bathymetry_fname best_density_contrast constraints_rmse inversion_rmse topo_improvement_rmse
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 4.089101 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1516.0 100.607651 72.304561 -25.983116
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 8.178203 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1675.0 196.916741 145.160338 -98.838892
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 12.267304 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1845.0 284.907328 209.025044 -162.703598
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 16.356405 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2149.0 352.124626 267.289107 -220.967662
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 46.321446 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 20.445507 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2538.0 405.236779 316.810444 -270.488998
[36]:
sampled_params_df.describe()
[36]:
constraint_numbers regional_strengths constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse regional_stdev best_density_contrast constraints_rmse inversion_rmse topo_improvement_rmse
count 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000
mean 149.900000 110.000000 0.083960 8.919700 25.135300 0.259203 330.933333 15.135699 26.063274 22.490057 2571.320000 378.276749 301.880583 -275.817309
std 200.751844 57.735027 0.095932 5.092535 14.650223 0.192085 66.431876 8.923908 14.282005 11.804219 706.209527 145.056577 120.556760 121.334007
min 4.000000 20.000000 0.003560 2.520000 6.333000 -0.144477 282.666667 3.335341 5.928079 4.089101 1508.000000 87.810057 72.078367 -442.968953
25% 12.000000 60.000000 0.006497 4.256000 12.387000 0.146099 285.333333 6.381553 11.358153 12.267304 1845.000000 281.310934 209.025392 -375.793658
50% 53.000000 110.000000 0.045115 7.956500 20.771500 0.277189 299.000000 13.749814 24.798910 22.490057 2731.500000 405.243568 335.137232 -305.955380
75% 210.000000 160.000000 0.131168 13.483000 38.792000 0.441687 350.000000 24.695177 41.525873 32.712811 3300.000000 493.912515 402.496779 -185.754519
max 650.000000 200.000000 0.283030 17.755000 51.305000 0.483691 496.666667 28.351063 46.321446 40.891013 3300.000000 580.498099 448.908124 -25.983116
[37]:
fig = synth_plotting.plot_2var_ensemble(
    sampled_params_df,
    figsize=(6, 4),
    x="median_proximity",
    x_title="Median proximity (km)",
    y="regional_stdev",
    y_title="Regional field standard deviation (mGal)",
    background="best_density_contrast",
    background_title="Optimal density contrast",
    background_robust=True,
    # logx=True,
    # flipx=True,
    constrained_layout=False,
)
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_41_0.png

Redo with optimal density

[38]:
for i, row in sampled_params_df.iterrows():
    # add results file name
    sampled_params_df.loc[i, "final_inversion_results_fname"] = (
        f"{ensemble_path}_final_inversion_{i}"
    )
    sampled_params_df.loc[i, "final_inverted_bathymetry_fname"] = (
        f"{ensemble_path}_final_inverted_bathymetry_{i}.nc"
    )

sampled_params_df.head()
[38]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae ... grav_df_fname regional_stdev results_fname inverted_bathymetry_fname best_density_contrast constraints_rmse inversion_rmse topo_improvement_rmse final_inversion_results_fname final_inverted_bathymetry_fname
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 4.089101 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1516.0 100.607651 72.304561 -25.983116 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 8.178203 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1675.0 196.916741 145.160338 -98.838892 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 12.267304 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1845.0 284.907328 209.025044 -162.703598 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 16.356405 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2149.0 352.124626 267.289107 -220.967662 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 20.445507 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2538.0 405.236779 316.810444 -270.488998 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl...

5 rows × 21 columns

[39]:
regional_grav_kwargs = dict(
    method="constraints",
    grid_method="pygmt",
    tension_factor=0,
)
[40]:
logging.getLogger().setLevel(logging.WARNING)

for i, row in tqdm(sampled_params_df.iterrows(), total=len(sampled_params_df)):
    # load data
    grav_df = pd.read_csv(row.grav_df_fname)
    starting_bathymetry = xr.open_dataarray(row.starting_bathymetry_fname)
    constraint_points = pd.read_csv(row.constraint_points_fname)

    # set kwargs to pass to the inversion
    kwargs = {
        # set stopping criteria
        "max_iterations": 200,
        "l2_norm_tolerance": 0.2**0.5,  # square root of the gravity noise
        "delta_l2_norm_tolerance": 1.008,
        "solver_damping": 0.025,
    }

    temp_reg_kwargs = copy.deepcopy(regional_grav_kwargs)
    temp_reg_kwargs["constraints_df"] = constraint_points

    # run the inversion workflow using the optimal damping and density values
    _ = inversion.run_inversion_workflow(
        grav_df=grav_df,
        density_contrast=row.best_density_contrast,
        zref=0,
        starting_topography=starting_bathymetry,
        regional_grav_kwargs=temp_reg_kwargs,
        fname=row.final_inversion_results_fname,
        create_starting_prisms=True,
        calculate_starting_gravity=True,
        calculate_regional_misfit=True,
        **kwargs,
    )

    sampled_params_df.head()
[41]:
for i, row in sampled_params_df.iterrows():
    # load data
    grav_df = pd.read_csv(row.grav_df_fname)
    starting_bathymetry = xr.load_dataarray(row.starting_bathymetry_fname)
    constraint_points = pd.read_csv(row.constraint_points_fname)

    # load saved inversion results
    with pathlib.Path(f"{row.final_inversion_results_fname}_results.pickle").open(
        "rb"
    ) as f:
        topo_results, grav_results, parameters, elapsed_time = pickle.load(f)

    final_bathymetry = topo_results.set_index(["northing", "easting"]).to_xarray().topo

    # sample the inverted topography at the constraint points
    constraint_points = utils.sample_grids(
        constraint_points,
        final_bathymetry,
        f"final_inverted_bathymetry_{i}",
        coord_names=("easting", "northing"),
    )
    constraints_rmse = utils.rmse(
        constraint_points.true_upward
        - constraint_points[f"final_inverted_bathymetry_{i}"]
    )

    # clip to inversion region
    final_bathymetry = final_bathymetry.sel(
        easting=slice(inversion_region[0], inversion_region[1]),
        northing=slice(inversion_region[2], inversion_region[3]),
    )

    inversion_rmse = utils.rmse(inside_bathymetry - final_bathymetry)

    # save final topography to file
    final_bathymetry.to_netcdf(row.final_inverted_bathymetry_fname)

    # add to dataframe
    sampled_params_df.loc[i, "final_inversion_constraints_rmse"] = constraints_rmse
    sampled_params_df.loc[i, "final_inversion_rmse"] = inversion_rmse

sampled_params_df.head()
[41]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae ... results_fname inverted_bathymetry_fname best_density_contrast constraints_rmse inversion_rmse topo_improvement_rmse final_inversion_results_fname final_inverted_bathymetry_fname final_inversion_constraints_rmse final_inversion_rmse
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1516.0 100.607651 72.304561 -25.983116 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1.415311 25.687797
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1675.0 196.916741 145.160338 -98.838892 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1.815615 47.128332
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1845.0 284.907328 209.025044 -162.703598 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2.232705 64.401993
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2149.0 352.124626 267.289107 -220.967662 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2.517473 73.013989
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2538.0 405.236779 316.810444 -270.488998 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2.669346 76.345720

5 rows × 23 columns

[42]:
sampled_params_df["final_inversion_topo_improvement_rmse"] = (
    sampled_params_df.starting_bathymetry_rmse - sampled_params_df.final_inversion_rmse
)
[43]:
sampled_params_df.to_csv(ensemble_fname, index=False)
[44]:
sampled_params_df = pd.read_csv(ensemble_fname)
sampled_params_df
[44]:
constraint_numbers regional_strengths constraint_points_fname starting_bathymetry_fname constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae ... inverted_bathymetry_fname best_density_contrast constraints_rmse inversion_rmse topo_improvement_rmse final_inversion_results_fname final_inverted_bathymetry_fname final_inversion_constraints_rmse final_inversion_rmse final_inversion_topo_improvement_rmse
0 4 20.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1516.0 100.607651 72.304561 -25.983116 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1.415311 25.687797 20.633648
1 4 40.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1675.0 196.916741 145.160338 -98.838892 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1.815615 47.128332 -0.806886
2 4 60.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 1845.0 284.907328 209.025044 -162.703598 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2.232705 64.401993 -18.080548
3 4 80.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2149.0 352.124626 267.289107 -220.967662 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2.517473 73.013989 -26.692543
4 4 100.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.00356 17.755 51.305 0.483691 282.666667 28.351063 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2538.0 405.236779 316.810444 -270.488998 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2.669346 76.345720 -30.024274
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
95 650 120.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667 3.335341 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 2925.0 402.633620 353.456330 -347.528251 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.797250 3.144191 2.783888
96 650 140.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667 3.335341 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 3147.0 432.309125 380.000105 -374.072026 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.820400 3.223230 2.704849
97 650 160.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667 3.335341 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 3300.0 458.394076 402.496493 -396.568414 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.834021 3.240482 2.687596
98 650 180.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667 3.335341 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 3300.0 489.076040 425.528815 -419.600736 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.839198 3.130741 2.797338
99 650 200.0 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.28303 2.520 6.333 -0.144477 496.666667 3.335341 ... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 3300.0 520.157398 448.897032 -442.968953 ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... ../results/Ross_Sea/ensembles/Ross_Sea_ensembl... 0.845232 3.023905 2.904174

100 rows × 24 columns

[45]:
sampled_params_df.columns
[45]:
Index(['constraint_numbers', 'regional_strengths', 'constraint_points_fname',
       'starting_bathymetry_fname', 'constraints_starting_rmse',
       'median_proximity', 'maximum_constraint_proximity',
       'constraint_proximity_skewness', 'constraints_per_10000sq_km',
       'starting_bathymetry_mae', 'starting_bathymetry_rmse', 'grav_df_fname',
       'regional_stdev', 'results_fname', 'inverted_bathymetry_fname',
       'best_density_contrast', 'constraints_rmse', 'inversion_rmse',
       'topo_improvement_rmse', 'final_inversion_results_fname',
       'final_inverted_bathymetry_fname', 'final_inversion_constraints_rmse',
       'final_inversion_rmse', 'final_inversion_topo_improvement_rmse'],
      dtype='object')
[46]:
sampled_params_df.describe()
[46]:
constraint_numbers regional_strengths constraints_starting_rmse median_proximity maximum_constraint_proximity constraint_proximity_skewness constraints_per_10000sq_km starting_bathymetry_mae starting_bathymetry_rmse regional_stdev best_density_contrast constraints_rmse inversion_rmse topo_improvement_rmse final_inversion_constraints_rmse final_inversion_rmse final_inversion_topo_improvement_rmse
count 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000 100.000000
mean 149.900000 110.000000 0.083960 8.919700 25.135300 0.259203 330.933333 15.135699 26.063274 22.490057 2571.320000 378.276749 301.880583 -275.817309 1.352146 20.939675 5.123598
std 200.751844 57.735027 0.095932 5.092535 14.650223 0.192085 66.431876 8.923908 14.282005 11.804219 706.209527 145.056577 120.556760 121.334007 0.676127 26.749476 18.491122
min 4.000000 20.000000 0.003560 2.520000 6.333000 -0.144477 282.666667 3.335341 5.928079 4.089101 1508.000000 87.810057 72.078367 -442.968953 0.317733 2.422900 -74.798134
25% 12.000000 60.000000 0.006497 4.256000 12.387000 0.146099 285.333333 6.381553 11.358153 12.267304 1845.000000 281.310934 209.025392 -375.793658 0.942693 4.084694 3.423253
50% 53.000000 110.000000 0.045115 7.956500 20.771500 0.277189 299.000000 13.749814 24.798910 22.490057 2731.500000 405.243568 335.137232 -305.955380 1.113127 8.185372 9.121957
75% 210.000000 160.000000 0.131168 13.483000 38.792000 0.441687 350.000000 24.695177 41.525873 32.712811 3300.000000 493.912515 402.496779 -185.754519 1.566824 25.812968 15.349237
max 650.000000 200.000000 0.283030 17.755000 51.305000 0.483691 496.666667 28.351063 46.321446 40.891013 3300.000000 580.498099 448.908124 -25.983116 3.718471 121.119580 31.614929

Examine results

[47]:
fig = synth_plotting.plot_2var_ensemble(
    sampled_params_df,
    figsize=(6, 4),
    x="median_proximity",
    x_title="Median proximity (km)",
    y="regional_stdev",
    y_title="Regional field standard deviation (mGal)",
    background="final_inversion_rmse",
    background_title="Bathymetry RMSE (m)",
    background_robust=True,
    # logx=True,
    # flipx=True,
    constrained_layout=False,
    plot_title="with optimal density",
)
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_53_0.png
[48]:
fig = synth_plotting.plot_2var_ensemble(
    sampled_params_df,
    figsize=(6, 4),
    x="median_proximity",
    x_title="Median proximity (km)",
    y="regional_stdev",
    y_title="Regional field standard deviation (mGal)",
    background="final_inversion_topo_improvement_rmse",
    background_title="Topo improvement (m)",
    background_cmap="cmo.balance_r",
    background_cpt_lims=polar_utils.get_min_max(
        sampled_params_df.final_inversion_topo_improvement_rmse,
        robust=True,
        absolute=True,
    ),
    plot_contours=[0],
    contour_color="black",
    constrained_layout=False,
    plot_title="with optimal density",
)
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_54_0.png
[49]:
fig = synth_plotting.plot_ensemble_as_lines(
    sampled_params_df,
    figsize=(6, 4),
    x="median_proximity",
    x_label="Median proximity (km)",
    # x="constraints_per_10000sq_km",
    # x_label="Constraints per $10000 km^2$",
    y="final_inversion_topo_improvement_rmse",
    y_label="Topo improvement (m)",
    groupby_col="regional_stdev",
    cbar_label="Regional gravity strength (mGal)",
    horizontal_line=0,
)
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_55_0.png
[50]:
fig = synth_plotting.plot_ensemble_as_lines(
    sampled_params_df,
    figsize=(4, 4),
    x="regional_stdev",
    x_label="Regional gravity strength (mGal)",
    y="final_inversion_rmse",
    y_label="Bathymetry RMSE (m)",
    groupby_col="median_proximity",
    cbar_label="Median proximity (km)",
    # groupby_col="constraints_per_10000sq_km",
    # cbar_label="Constraints per $10000 km^2$",
    trend_line=True,
    # slope_min_max=True,
    # slope_mean=True,
)
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_56_0.png
[51]:
fig = synth_plotting.plot_ensemble_as_lines(
    sampled_params_df,
    figsize=(4, 4),
    x="regional_stdev",
    x_label="Regional gravity strength (mGal)",
    y="final_inversion_topo_improvement_rmse",
    y_label="Topo improvement (m)",
    groupby_col="median_proximity",
    cbar_label="Median proximity (km)",
    # groupby_col="constraints_per_10000sq_km",
    # cbar_label="Constraints per $10000 km^2$",
    trend_line=True,
    horizontal_line=0,
    # slope_min_max=True,
    # slope_mean=True,
)
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_57_0.png
[52]:
metric = "median_proximity"
grids = []
names = []
for i, row in tqdm(sampled_params_df.iterrows(), total=len(sampled_params_df)):
    # load saved inversion results
    with pathlib.Path(f"{row.final_inversion_results_fname}_results.pickle").open(
        "rb"
    ) as f:
        topo_results, grav_results, parameters, elapsed_time = pickle.load(f)

    final_bathymetry = topo_results.set_index(["northing", "easting"]).to_xarray().topo

    grd = inside_bathymetry - final_bathymetry

    grids.append(grd)
    names.append(round(row[metric], 1))

raps_das = []
for i, g in enumerate(grids):
    raps_das.append(
        xrft.isotropic_power_spectrum(
            g,
            dim=["easting", "northing"],
            # detrend='constant',
            detrend="linear",
            # window=False,
            # nfactor=4,
            # spacing_tol=0.01,
            # nfactor=3,
            truncate=False,
        )
    )

fig, ax = plt.subplots(figsize=(5, 3.5))

norm = plt.Normalize(
    vmin=sampled_params_df[metric].min(),
    vmax=sampled_params_df[metric].max(),
)

max_powers = []
max_power_wavelengths = []
for i, da in enumerate(raps_das):
    ax.plot(
        (1 / da.freq_r) / 1e3,
        da,
        label=names[i],
        color=plt.cm.viridis(norm([names[i]])),
    )
    max_ind = da.idxmax()
    max_power = da.max().to_numpy()
    max_power_wavelength = 1 / (da[da == max_power].freq_r.to_numpy()[0]) / 1e3
    max_power_wavelengths.append(max_power_wavelength)
    max_powers.append(max_power)
    ax.scatter(
        x=max_power_wavelength,
        y=max_power,
        marker="*",
        edgecolor="black",
        linewidth=0.5,
        color=plt.cm.viridis(norm(names[i])),  # pylint: disable=no-member
        s=60,
        zorder=20,
    )
    # print(f"Max y value at x value: {max_power_wavelength}")

# ax.set_xscale("log")
ax.set_yscale("log")

ax.legend(title=metric, loc="center left", bbox_to_anchor=(1, 0.5))

ax.set_xlabel("Wavelength (km)")
ax.set_ylabel("Power ($m^3$)")
ax.set_title("Radially averaged PSD of inverted bed errors")
plt.tight_layout()

# ax.xaxis.set_major_formatter(mpl.ticker.StrMethodFormatter("{x:.1f}"))
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_58_1.png
[53]:
y = max_power_wavelengths
x = names

m, b = np.polyfit(
    x,
    y,
    1,
)

plt.scatter(
    x,
    y,
)

# plot y = m*x + b
plt.axline(xy1=(0, b), slope=m, label=f"$y = {m:.3f}x {b:+.3f}$")
plt.legend()
[53]:
<matplotlib.legend.Legend at 0x7f348c2307a0>
_images/ensemble_01_constraint_spacing_vs_regional_strength_density_estimation_59_1.png