[1]:
%load_ext autoreload
%autoreload 2
[2]:
import xarray as xr
import xgcm
import matplotlib.pyplot as plt

Tutorial: analyzing finite-volume ocean model budgets with xbudget

This tutorial shows how to use xbudget to close and manipulate mass and tracer budgets in finite-volume.

Load example MOM6 dataset from Zenodo

[3]:
from load_example_model_grid import load_MOM6_coarsened_diagnostics
grid = load_MOM6_coarsened_diagnostics()
File 'MOM6_global_example_diagnostics_zlevels_v0_0_6.nc' already exists at ../data/MOM6_global_example_diagnostics_zlevels_v0_0_6.nc. Skipping download.

Load budget metadata from preset MOM6 dictionary

[4]:
import xbudget
xbudget_dict = xbudget.load_preset_budget(model="MOM6").copy()

We load in the file xbudget/conventions/MOM6.yaml, which comprehensively details the mass, heat, and salt budgets in MOM6, and how they can be evaluated using various combinations of diagnostics. In MOM6, most mass and tracer diagnostics are output as thickness tendencies and thickness-weighted tracer tendencies, respectively, and must be converted into density-weighted integrals over a finite-volume cell by multiplying by a seawater density and grid cell area.

For example, consider the structure of the heat budget:

[5]:
import json
print(json.dumps(xbudget_dict['heat'], sort_keys=True, indent=4))
{
    "lambda": "thetao",
    "lhs": {
        "sum": {
            "Eulerian_tendency": {
                "product": {
                    "area": "areacello",
                    "tracer_content_tendency_per_unit_area": "opottemptend",
                    "var": null
                },
                "var": null
            },
            "advection": {
                "sum": {
                    "interfacial": {
                        "product": {
                            "area": "areacello",
                            "sign": -1.0,
                            "tracer_content_tendency_per_unit_area": "Th_tendency_vert_remap",
                            "var": null
                        },
                        "var": null
                    },
                    "lateral": {
                        "product": {
                            "area": "areacello",
                            "sign": -1.0,
                            "tracer_content_tendency_per_unit_area": "T_advection_xy",
                            "var": null
                        },
                        "var": null
                    },
                    "var": null
                },
                "var": null
            },
            "surface_ocean_flux_advective_negative_lhs": {
                "product": {
                    "area": "areacello",
                    "density": 1035.0,
                    "lambda_mass": "tos",
                    "sign": -1.0,
                    "specific_heat_capacity": 3992.0,
                    "thickness_tendency": "boundary_forcing_h_tendency",
                    "var": null
                },
                "var": null
            },
            "var": null
        },
        "var": null
    },
    "rhs": {
        "sum": {
            "bottom_flux": {
                "product": {
                    "area": "areacello",
                    "tracer_content_tendency_per_unit_area": "internal_heat_heat_tendency",
                    "var": null
                },
                "var": null
            },
            "diffusion": {
                "sum": {
                    "interfacial": {
                        "product": {
                            "area": "areacello",
                            "tracer_content_tendency_per_unit_area": "opottempdiff",
                            "var": null
                        },
                        "var": null
                    },
                    "lateral": {
                        "product": {
                            "area": "areacello",
                            "tracer_content_tendency_per_unit_area": "opottemppmdiff",
                            "var": null
                        },
                        "var": null
                    },
                    "var": null
                },
                "var": null
            },
            "frazil_ice": {
                "product": {
                    "area": "areacello",
                    "tracer_content_tendency_per_unit_area": "frazil_heat_tendency",
                    "var": null
                },
                "var": null
            },
            "surface_exchange_flux": {
                "product": {
                    "area": "areacello",
                    "tracer_content_tendency_per_unit_area": "boundary_forcing_heat_tendency",
                    "var": null
                },
                "sum": {
                    "advective": {
                        "product": {
                            "area": "areacello",
                            "tracer_content_tendency_per_unit_area": "heat_content_surfwater",
                            "var": null
                        },
                        "var": null
                    },
                    "nonadvective": {
                        "sum": {
                            "latent": {
                                "product": {
                                    "area": "areacello",
                                    "tracer_content_tendency_per_unit_area": "hflso",
                                    "var": null
                                },
                                "var": null
                            },
                            "longwave": {
                                "product": {
                                    "area": "areacello",
                                    "tracer_content_tendency_per_unit_area": "rlntds",
                                    "var": null
                                },
                                "var": null
                            },
                            "sensible": {
                                "product": {
                                    "area": "areacello",
                                    "tracer_content_tendency_per_unit_area": "hfsso",
                                    "var": null
                                },
                                "var": null
                            },
                            "shortwave": {
                                "product": {
                                    "area": "areacello",
                                    "tracer_content_tendency_per_unit_area": "rsdoabsorb",
                                    "var": null
                                },
                                "var": null
                            },
                            "var": null
                        },
                        "var": null
                    },
                    "var": null
                },
                "var": null
            },
            "surface_ocean_flux_advective_negative_rhs": {
                "product": {
                    "area": "areacello",
                    "density": 1035.0,
                    "lambda_mass": "tos",
                    "sign": -1.0,
                    "specific_heat_capacity": 3992.0,
                    "thickness_tendency": "boundary_forcing_h_tendency",
                    "var": null
                },
                "var": null
            },
            "var": null
        },
        "var": null
    },
    "surface_lambda": "tos"
}

The var: null entries in the dictionary denote where diagnostics are not directly available. In many cases, however, they can be reconstructed by taking the sum or product of available diagnostics.

We can use the xbudget.collect_budgets function to leverage the information in this metadata dictionary to fill in all of these gaps in the budget.

[6]:
xbudget.collect_budgets(grid, xbudget_dict)

All of these reconstructed budget terms are also automatically (and lazily) added to the original dataset with a straight-forward naming convention, so they can be used directly to evaluate the budget.

[7]:
import json
print(json.dumps(xbudget_dict['heat'], sort_keys=True, indent=4))
{
    "lambda": "thetao",
    "lhs": {
        "sum": {
            "Eulerian_tendency": {
                "product": {
                    "area": "areacello",
                    "tracer_content_tendency_per_unit_area": "opottemptend",
                    "var": "heat_lhs_sum_Eulerian_tendency_product"
                },
                "var": "heat_lhs_sum_Eulerian_tendency"
            },
            "advection": {
                "sum": {
                    "interfacial": {
                        "product": {
                            "area": "areacello",
                            "sign": -1.0,
                            "tracer_content_tendency_per_unit_area": "Th_tendency_vert_remap",
                            "var": "heat_lhs_sum_advection_sum_interfacial_product"
                        },
                        "var": "heat_lhs_sum_advection_sum_interfacial"
                    },
                    "lateral": {
                        "product": {
                            "area": "areacello",
                            "sign": -1.0,
                            "tracer_content_tendency_per_unit_area": "T_advection_xy",
                            "var": "heat_lhs_sum_advection_sum_lateral_product"
                        },
                        "var": "heat_lhs_sum_advection_sum_lateral"
                    },
                    "var": "heat_lhs_sum_advection_sum"
                },
                "var": "heat_lhs_sum_advection"
            },
            "surface_ocean_flux_advective_negative_lhs": {
                "product": {
                    "area": "areacello",
                    "density": 1035.0,
                    "lambda_mass": "tos",
                    "sign": -1.0,
                    "specific_heat_capacity": 3992.0,
                    "thickness_tendency": "boundary_forcing_h_tendency",
                    "var": "heat_lhs_sum_surface_ocean_flux_advective_negative_lhs_product"
                },
                "var": "heat_lhs_sum_surface_ocean_flux_advective_negative_lhs"
            },
            "var": "heat_lhs_sum"
        },
        "var": "heat_lhs"
    },
    "rhs": {
        "sum": {
            "bottom_flux": {
                "product": {
                    "area": "areacello",
                    "tracer_content_tendency_per_unit_area": "internal_heat_heat_tendency",
                    "var": "heat_rhs_sum_bottom_flux_product"
                },
                "var": "heat_rhs_sum_bottom_flux"
            },
            "diffusion": {
                "sum": {
                    "interfacial": {
                        "product": {
                            "area": "areacello",
                            "tracer_content_tendency_per_unit_area": "opottempdiff",
                            "var": "heat_rhs_sum_diffusion_sum_interfacial_product"
                        },
                        "var": "heat_rhs_sum_diffusion_sum_interfacial"
                    },
                    "lateral": {
                        "product": {
                            "area": "areacello",
                            "tracer_content_tendency_per_unit_area": "opottemppmdiff",
                            "var": "heat_rhs_sum_diffusion_sum_lateral_product"
                        },
                        "var": "heat_rhs_sum_diffusion_sum_lateral"
                    },
                    "var": "heat_rhs_sum_diffusion_sum"
                },
                "var": "heat_rhs_sum_diffusion"
            },
            "frazil_ice": {
                "product": {
                    "area": "areacello",
                    "tracer_content_tendency_per_unit_area": "frazil_heat_tendency",
                    "var": "heat_rhs_sum_frazil_ice_product"
                },
                "var": "heat_rhs_sum_frazil_ice"
            },
            "surface_exchange_flux": {
                "product": {
                    "area": "areacello",
                    "tracer_content_tendency_per_unit_area": "boundary_forcing_heat_tendency",
                    "var": "heat_rhs_sum_surface_exchange_flux_product"
                },
                "sum": {
                    "advective": {
                        "product": {
                            "area": "areacello",
                            "tracer_content_tendency_per_unit_area": "heat_content_surfwater",
                            "var": "heat_rhs_sum_surface_exchange_flux_sum_advective_product"
                        },
                        "var": "heat_rhs_sum_surface_exchange_flux_sum_advective"
                    },
                    "nonadvective": {
                        "sum": {
                            "latent": {
                                "product": {
                                    "area": "areacello",
                                    "tracer_content_tendency_per_unit_area": "hflso",
                                    "var": "heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_latent_product"
                                },
                                "var": "heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_latent"
                            },
                            "longwave": {
                                "product": {
                                    "area": "areacello",
                                    "tracer_content_tendency_per_unit_area": "rlntds",
                                    "var": "heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_longwave_product"
                                },
                                "var": "heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_longwave"
                            },
                            "sensible": {
                                "product": {
                                    "area": "areacello",
                                    "tracer_content_tendency_per_unit_area": "hfsso",
                                    "var": "heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_sensible_product"
                                },
                                "var": "heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_sensible"
                            },
                            "shortwave": {
                                "product": {
                                    "area": "areacello",
                                    "tracer_content_tendency_per_unit_area": "rsdoabsorb",
                                    "var": "heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_shortwave_product"
                                },
                                "var": "heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_shortwave"
                            },
                            "var": "heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum"
                        },
                        "var": "heat_rhs_sum_surface_exchange_flux_sum_nonadvective"
                    },
                    "var": "heat_rhs_sum_surface_exchange_flux_sum"
                },
                "var": "heat_rhs_sum_surface_exchange_flux"
            },
            "surface_ocean_flux_advective_negative_rhs": {
                "product": {
                    "area": "areacello",
                    "density": 1035.0,
                    "lambda_mass": "tos",
                    "sign": -1.0,
                    "specific_heat_capacity": 3992.0,
                    "thickness_tendency": "boundary_forcing_h_tendency",
                    "var": "heat_rhs_sum_surface_ocean_flux_advective_negative_rhs_product"
                },
                "var": "heat_rhs_sum_surface_ocean_flux_advective_negative_rhs"
            },
            "var": "heat_rhs_sum"
        },
        "var": "heat_rhs"
    },
    "surface_lambda": "tos"
}

Because searching through this data structure by eye can be tedious, we include helpers functions to help retrieve the variable name corresponding to each term in the budget.

[8]:
from xbudget import get_vars
grid._ds[get_vars(xbudget_dict, "heat_lhs_sum_advection")['var']]
[8]:
<xarray.DataArray 'heat_lhs_sum_advection' (time: 1, z_l: 35, yh: 180, xh: 240)> Size: 12MB
array([[[[0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         ...,
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.]],

        [[0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         ...,
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.]],

        [[0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         ...,
...
         ...,
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.]],

        [[0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         ...,
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.]],

        [[0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         ...,
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.]]]], shape=(1, 35, 180, 240))
Coordinates:
  * time       (time) object 8B 2000-07-01 00:00:00
  * z_l        (z_l) float64 280B 2.5 10.0 20.0 32.5 ... 5.5e+03 6e+03 6.5e+03
  * yh         (yh) int64 1kB 0 1 2 3 4 5 6 7 ... 173 174 175 176 177 178 179
  * xh         (xh) int64 2kB 0 1 2 3 4 5 6 7 ... 233 234 235 236 237 238 239
    geolon     (yh, xh) float64 346kB ...
    lon        (yh, xh) float64 346kB ...
    geolat     (yh, xh) float64 346kB ...
    lat        (yh, xh) float64 346kB ...
    deptho     (yh, xh) float32 173kB ...
    wet        (yh, xh) float32 173kB ...
    areacello  (yh, xh) float64 346kB ...
Attributes:
    cell_measures:  volume: volcello area: areacello
    time_avg_info:  average_T1,average_T2,average_DT
    standard_name:  cell_area
    note:           We ignore land cells in partially wet cells when coarseni...
    provenance:     heat_lhs_sum_advection_sum

If the variable is not immediately available as a diagnostic–but instead derived from other diagnostics–the provenance attribute points to the origin of the variable.

For variables that are the sum or product of other terms, get_vars also returns a list of the variables that feed into the operation:

[9]:
get_vars(xbudget_dict, "heat_lhs_sum_advection_sum")
[9]:
{'var': 'heat_lhs_sum_advection_sum',
 'sum': ['heat_lhs_sum_advection_sum_lateral',
  'heat_lhs_sum_advection_sum_interfacial']}

The terms from which the variable is derived are not necessarily other xr.DataArray objects–they can also be constant numbers.

[10]:
get_vars(xbudget_dict, "heat_lhs_sum_surface_ocean_flux_advective_negative_lhs_product")
[10]:
{'var': 'heat_lhs_sum_surface_ocean_flux_advective_negative_lhs_product',
 'product': [-1.0,
  3992.0,
  'tos',
  'boundary_forcing_h_tendency',
  1035.0,
  'areacello']}

The get_vars functions takes either a string or a list of strings:

[11]:
get_vars(xbudget_dict, ["heat_lhs", "heat_rhs_sum_diffusion_sum", "boundary_forcing_heat_tendency"])
[11]:
[{'var': 'heat_lhs'},
 {'var': 'heat_rhs_sum_diffusion_sum',
  'sum': ['heat_rhs_sum_diffusion_sum_lateral',
   'heat_rhs_sum_diffusion_sum_interfacial']},
 {'var': 'boundary_forcing_heat_tendency'}]

Verification that the budgets close

We compare the left-hand-side (LHS) tendency terms against the sum of all of the right-hand-side (RHS) terms.

[12]:
for eq, vmax in zip(["mass", "heat", "salt"], [1.e4, 1e12, 1.e5]):
    plt.figure(figsize=(10, 4))

    plt.subplot(1,2,1)
    pc = grid._ds[get_vars(xbudget_dict, f"{eq}_lhs")['var']].isel(z_l = 0).isel(time=0).plot(vmin=-vmax, vmax=vmax, cmap="RdBu_r")
    plt.title(f"LHS {eq} tendency")

    plt.subplot(1,2,2)
    pc = grid._ds[get_vars(xbudget_dict, f"{eq}_rhs")['var']].isel(z_l = 0).isel(time=0).plot(vmin=-vmax, vmax=vmax, cmap="RdBu_r")
    plt.title(f"RHS {eq} tendency")

    plt.tight_layout()
../_images/examples_MOM6_budget_examples_mass_heat_salt_23_0.png
../_images/examples_MOM6_budget_examples_mass_heat_salt_23_1.png
../_images/examples_MOM6_budget_examples_mass_heat_salt_23_2.png

Decompose RHS budget terms with xbudget

Since the full budget is relatively clunky and can be decomposed in a number of different ways, we include helper functions for collecting all of the high-level terms and optionally dissaggreating terms of interest:

[13]:
# Default high-level aggregate budget
simple_budgets = xbudget.aggregate(xbudget_dict)
simple_budgets
[13]:
{'mass': {'lambda': 'density',
  'thickness': 'thkcello',
  'lhs': {'Eulerian_tendency': 'mass_lhs_sum_Eulerian_tendency'},
  'rhs': {'advection': 'mass_rhs_sum_advection',
   'surface_exchange_flux': 'mass_rhs_sum_surface_exchange_flux'}},
 'heat': {'lambda': 'thetao',
  'surface_lambda': 'tos',
  'lhs': {'Eulerian_tendency': 'heat_lhs_sum_Eulerian_tendency',
   'advection': 'heat_lhs_sum_advection',
   'surface_ocean_flux_advective_negative_lhs': 'heat_lhs_sum_surface_ocean_flux_advective_negative_lhs'},
  'rhs': {'diffusion': 'heat_rhs_sum_diffusion',
   'surface_exchange_flux': 'heat_rhs_sum_surface_exchange_flux',
   'surface_ocean_flux_advective_negative_rhs': 'heat_rhs_sum_surface_ocean_flux_advective_negative_rhs',
   'bottom_flux': 'heat_rhs_sum_bottom_flux',
   'frazil_ice': 'heat_rhs_sum_frazil_ice'}},
 'salt': {'lambda': 'so',
  'surface_lambda': 'sos',
  'lhs': {'Eulerian_tendency': 'salt_lhs_sum_Eulerian_tendency',
   'advection': 'salt_lhs_sum_advection',
   'surface_ocean_flux_advective_negative_lhs': 'salt_lhs_sum_surface_ocean_flux_advective_negative_lhs'},
  'rhs': {'diffusion': 'salt_rhs_sum_diffusion',
   'surface_exchange_flux': 'salt_rhs_sum_surface_exchange_flux',
   'surface_ocean_flux_advective_negative_rhs': 'salt_rhs_sum_surface_ocean_flux_advective_negative_rhs'}}}
[14]:
vmax = 1.e-4

for eq, vmax in zip(["mass", "heat", "salt"], [1.e6, 1e12, 1e4]):
    N = len(simple_budgets[eq]['rhs'])
    plt.figure(figsize=(5*N, 4))
    for i, (k,v) in enumerate(simple_budgets[eq]['rhs'].items(), start=1):
        plt.subplot(1,N, i)
        if "z_l" in grid._ds[v].dims:
            grid._ds[v].isel(z_l = 0).isel(time=0).plot(vmin=-vmax, vmax=vmax, cmap="RdBu_r")
        else:
            grid._ds[v].isel(time=0).plot(vmin=-vmax, vmax=vmax, cmap="RdBu_r")
        plt.title(f"{eq} {k}")

    plt.tight_layout()
../_images/examples_MOM6_budget_examples_mass_heat_salt_27_0.png
../_images/examples_MOM6_budget_examples_mass_heat_salt_27_1.png
../_images/examples_MOM6_budget_examples_mass_heat_salt_27_2.png

Custom budget decompositions

Suppose we want to have a better understanding of the processes driving both the surface_flux terms and interior diffusion terms. We can simply pass the list of these process names to the decompose keyword argument. We can also further breakdown the nonadvective part of the surface_flux term.

[15]:
decomposed_budgets = xbudget.aggregate(xbudget_dict, decompose=["surface_exchange_flux", "nonadvective", "diffusion"])
decomposed_budgets
[15]:
{'mass': {'lambda': 'density',
  'thickness': 'thkcello',
  'lhs': {'Eulerian_tendency': 'mass_lhs_sum_Eulerian_tendency'},
  'rhs': {'advection': 'mass_rhs_sum_advection',
   'surface_exchange_flux_rain_and_ice': 'mass_rhs_sum_surface_exchange_flux_sum_rain_and_ice',
   'surface_exchange_flux_snow': 'mass_rhs_sum_surface_exchange_flux_sum_snow',
   'surface_exchange_flux_evaporation': 'mass_rhs_sum_surface_exchange_flux_sum_evaporation',
   'surface_exchange_flux_rivers': 'mass_rhs_sum_surface_exchange_flux_sum_rivers',
   'surface_exchange_flux_icebergs': 'mass_rhs_sum_surface_exchange_flux_sum_icebergs',
   'surface_exchange_flux_sea_ice_melt': 'mass_rhs_sum_surface_exchange_flux_sum_sea_ice_melt',
   'surface_exchange_flux_virtual_precip_restoring': 'mass_rhs_sum_surface_exchange_flux_sum_virtual_precip_restoring'}},
 'heat': {'lambda': 'thetao',
  'surface_lambda': 'tos',
  'lhs': {'Eulerian_tendency': 'heat_lhs_sum_Eulerian_tendency',
   'advection': 'heat_lhs_sum_advection',
   'surface_ocean_flux_advective_negative_lhs': 'heat_lhs_sum_surface_ocean_flux_advective_negative_lhs'},
  'rhs': {'diffusion_lateral': 'heat_rhs_sum_diffusion_sum_lateral',
   'diffusion_interfacial': 'heat_rhs_sum_diffusion_sum_interfacial',
   'surface_exchange_flux_nonadvective_latent': 'heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_latent',
   'surface_exchange_flux_nonadvective_sensible': 'heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_sensible',
   'surface_exchange_flux_nonadvective_longwave': 'heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_longwave',
   'surface_exchange_flux_nonadvective_shortwave': 'heat_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_shortwave',
   'surface_exchange_flux_advective': 'heat_rhs_sum_surface_exchange_flux_sum_advective',
   'surface_ocean_flux_advective_negative_rhs': 'heat_rhs_sum_surface_ocean_flux_advective_negative_rhs',
   'bottom_flux': 'heat_rhs_sum_bottom_flux',
   'frazil_ice': 'heat_rhs_sum_frazil_ice'}},
 'salt': {'lambda': 'so',
  'surface_lambda': 'sos',
  'lhs': {'Eulerian_tendency': 'salt_lhs_sum_Eulerian_tendency',
   'advection': 'salt_lhs_sum_advection',
   'surface_ocean_flux_advective_negative_lhs': 'salt_lhs_sum_surface_ocean_flux_advective_negative_lhs'},
  'rhs': {'diffusion_lateral': 'salt_rhs_sum_diffusion_sum_lateral',
   'diffusion_interfacial': 'salt_rhs_sum_diffusion_sum_interfacial',
   'surface_exchange_flux_nonadvective_basal': 'salt_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_basal',
   'surface_exchange_flux_advective': 'salt_rhs_sum_surface_exchange_flux_sum_advective',
   'surface_ocean_flux_advective_negative_rhs': 'salt_rhs_sum_surface_ocean_flux_advective_negative_rhs'}}}
[16]:
decomposed_budgets[eq]['rhs']
[16]:
{'diffusion_lateral': 'salt_rhs_sum_diffusion_sum_lateral',
 'diffusion_interfacial': 'salt_rhs_sum_diffusion_sum_interfacial',
 'surface_exchange_flux_nonadvective_basal': 'salt_rhs_sum_surface_exchange_flux_sum_nonadvective_sum_basal',
 'surface_exchange_flux_advective': 'salt_rhs_sum_surface_exchange_flux_sum_advective',
 'surface_ocean_flux_advective_negative_rhs': 'salt_rhs_sum_surface_ocean_flux_advective_negative_rhs'}
[17]:
vmax = 1.e-4
import numpy as np

for eq, vmax in zip(["mass", "heat", "salt"], [1e6, 1e12, 1e4]):
    nrow = np.int64(np.ceil(len(decomposed_budgets[eq]['rhs'])/2))
    plt.figure(figsize=(12, nrow*4))
    for i, (k,v) in enumerate(decomposed_budgets[eq]['rhs'].items(), start=1):
        plt.subplot(nrow, 2, i)
        if "z_l" in grid._ds[v].dims:
            grid._ds[v].isel(z_l = 0).isel(time=0).plot(vmin=-vmax, vmax=vmax, cmap="RdBu_r")
        else:
            grid._ds[v].isel(time=0).plot(vmin=-vmax, vmax=vmax, cmap="RdBu_r")
        plt.title(f"{eq} {k}")

    plt.tight_layout()
    plt.show()
../_images/examples_MOM6_budget_examples_mass_heat_salt_31_0.png
../_images/examples_MOM6_budget_examples_mass_heat_salt_31_1.png
../_images/examples_MOM6_budget_examples_mass_heat_salt_31_2.png
[ ]: