Creating Carbon Dioxide Removal (CDR) Forcing#

This notebook demonstrates how to create Carbon Dioxide Removal (CDR) forcing for a ROMS-MARBL simulation. CDR forcing involves specifying one or more CDR releases within a single ROMS-MARBL run.

We will walk through the following steps:

  • Defining a CDR release

  • Creating CDR forcing from one or more releases

  • Visualizing the CDR forcing

  • Saving CDR forcing to NetCDF and YAML

  • Reconstructing CDR forcing from a YAML file

Creating a Release#

CDR forcing in ROMS-Tools begins with defining a CDR release. Two types are supported:

  • VolumeRelease: Injects both water and biogeochemical (BGC) tracers at a specific location (e.g., an underwater pipe).

    • Introduces volume flux and tracer concentrations.

    • Designed for field-scale deployments where mixing still needs to occur.

    • Requires concentration of all 32 MARBL BGC tracers, plus temperature and salinity (defaults available).

  • TracerPerturbation: Perturbs BGC tracer fields without adding water (i.e., no volume flux).

    • Introduces tracer fluxes, but no volume flux.

    • Designed for large-scale applications where mixing has already occurred (e.g., via a pre-run mixing model).

    • Of the 32 MARBL BGC tracers plus temperature and salinity, only the specified tracers are modified; the rest remain unchanged (equivalent to a perturbation of zero).

Specifying Location and Spread#

Both release types require the following parameters to define the release location:

  • lat: Latitude (in degrees North)

  • lon: Longitude (in degrees East)

  • depth: Depth (in meters)

  • hsc: Horizontal scale / standard deviation (in meters)

  • vsc: Vertical scale / standard deviation (in meters)

By default, hsc = vsc = 0, resulting in a point source (single grid cell). If hsc or vsc are greater than zero, the release is spread using a Gaussian.

Notes

  • A VolumeRelease applied over a broad area (hsc >> 0 or vsc >> 0, larger than the grid scale) can destabilize the model due to distributed buoyancy changes. It is best used as a point source (hsc = vsc = 0).

  • TracerPerturbation can safely span larger areas—provided temperature and salinity are not perturbed—since it does not affect buoyancy. A common use case is perturbing alkalinity (ALK) or dissolved inorganic carbon (DIC) with a Gaussian profile (hsc >> 0, vsc >> 0) to represent a well-mixed plume.

  • Note that using hsc much smaller than the grid resolution will result in a point source release.

[1]:
from datetime import datetime

Defining a VolumeRelease#

This section covers how to configure and use the VolumeRelease class to represent localized injections of water and tracers in a ROMS simulation.

In addition to the location parameters, a VolumeRelease has two key fields:

  • volume_fluxes

  • tracer_concentrations

Both can be specified as either constant or time-varying.

[2]:
from roms_tools import VolumeRelease

Call .get_metadata() to view the expected units for each tracer concentration.

[3]:
VolumeRelease.get_metadata()
[3]:
temp salt PO4 NO3 SiO3 NH4 Fe Lig O2 DIC DIC_ALT_CO2 ALK ALK_ALT_CO2 DOC DON DOP DOPr DONr DOCr zooC spChl spC spP spFe spCaCO3 diatChl diatC diatP diatFe diatSi diazChl diazC diazP diazFe
units degrees Celsius PSU mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 meq/m^3 meq/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mg/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mg/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mmol/m^3 mg/m^3 mmol/m^3 mmol/m^3 mmol/m^3
long_name potential temperature salinity dissolved inorganic phosphate dissolved inorganic nitrate dissolved inorganic silicate dissolved ammonia dissolved inorganic iron iron binding ligand dissolved oxygen dissolved inorganic carbon dissolved inorganic carbon, alternative CO2 alkalinity alkalinity, alternative CO2 dissolved organic carbon dissolved organic nitrogen dissolved organic phosphorus refractory dissolved organic phosphorus refractory dissolved organic nitrogen refractory dissolved organic carbon zooplankton carbon small phytoplankton chlorophyll small phytoplankton carbon small phytoplankton phosphorous small phytoplankton iron small phytoplankton CaCO3 diatom chloropyll diatom carbon diatom phosphorus diatom iron diatom silicate diazotroph chloropyll diazotroph carbon diazotroph phosphorus diazotroph iron

Constant volume flux and tracer concentrations#

Here we define a point source release close to Iceland with a volume flux and tracer concentrations that remain constant over time:

  • Volume flux: 1000 m³/s

  • Temperature: 20°C

  • Salinity: 1 PSU

  • Alkalinity concentration: 2000 meq/m³

These values will be applied throughout the entire ROMS simulation period.

[4]:
constant_volume_release_iceland = VolumeRelease(
    name="iceland_release",
    lat=65.0,  # degree N
    lon=-10,  # degree E
    depth=100,  # m
    volume_fluxes=1000,  # m3/s
    tracer_concentrations={
        "temp": 20.0,  # degrees C
        "salt": 1.0,  # psu
        "ALK": 2000.0,  # meq/m3
    },
)

Time-varying volume flux and tracer concentrations#

To define a time-varying release, specify the times parameter with explicit time points corresponding to the volume fluxes and tracer concentrations.

In the example below, both volume flux and alkalinity concentration vary over time, provided as lists matching the length of times. Meanwhile, temperature and salinity remain constant throughout the simulation period.

Note

Intermediate volume flux and tracer concentration values between the specified times are linearly interpolated when the CDRForcing object is constructed later.

[5]:
times = [
    datetime(2011, 1, 15, 12, 0),
    datetime(2011, 1, 15, 15, 0),
    datetime(2011, 1, 15, 18, 0),
    datetime(2011, 1, 19, 0, 0),
    datetime(2011, 1, 22, 6, 0),
    datetime(2011, 1, 22, 9, 0),
    datetime(2011, 1, 22, 12, 0),
]  # 7 entries
volume_fluxes = [0, 100, 500, 1000, 500, 100, 0]  # m3/s, 7 entries
tracer_concentrations = {
    "ALK": [
        1900.0,  # meq/m3
        2100.0,  # meq/m3
        2100.0,  # meq/m3
        2100.0,  # meq/m3
        2100.0,  # meq/m3
        2100.0,  # meq/m3
        1900.0,  # meq/m3
    ],  # 7 entries
    "temp": 20.0,  # degrees C
    "salt": 1.0,  # psu
}
[6]:
volume_release_greenland = VolumeRelease(
    name="greenland_release",
    lat=70.0,  # degree N
    lon=-20.0,  # degree E
    depth=100,  # m
    times=times,
    volume_fluxes=volume_fluxes,
    tracer_concentrations=tracer_concentrations,
)

Auto-fill vs. Zero-fill#

As noted earlier, ROMS requires concentrations for all 32 BGC tracers, plus temperature and salinity, when defining a VolumeRelease. If you don’t specify values for all tracers, use the fill_values parameter to control how the missing ones are handled:

  • fill_values = "auto" (default): Fills unspecified tracer concentrations with non-zero default values.

  • fill_values = "zero": Sets all unspecified tracer concentrations to zero.

All previous examples used the default ("auto"), which you can verify by checking the fill values for tracers other than temp, salt, and ALK below.

[7]:
volume_release_greenland
[7]:
VolumeRelease(name='greenland_release', lat=70.0, lon=-20.0, depth=100.0, hsc=0.0, vsc=0.0, times=[datetime.datetime(2011, 1, 15, 12, 0), datetime.datetime(2011, 1, 15, 15, 0), datetime.datetime(2011, 1, 15, 18, 0), datetime.datetime(2011, 1, 19, 0, 0), datetime.datetime(2011, 1, 22, 6, 0), datetime.datetime(2011, 1, 22, 9, 0), datetime.datetime(2011, 1, 22, 12, 0)], time_interpolation=False, release_type=<ReleaseType.volume: 'volume'>, fill_values='auto', volume_fluxes=Flux(name='volume', values=[0.0, 100.0, 500.0, 1000.0, 500.0, 100.0, 0.0]), tracer_concentrations={'ALK': Concentration(name='ALK', values=[1900.0, 2100.0, 2100.0, 2100.0, 2100.0, 2100.0, 1900.0]), 'temp': Concentration(name='temp', values=20.0), 'salt': Concentration(name='salt', values=1.0), 'PO4': Concentration(name='PO4', values=2.7), 'NO3': Concentration(name='NO3', values=24.2), 'SiO3': Concentration(name='SiO3', values=13.2), 'NH4': Concentration(name='NH4', values=2.2), 'Fe': Concentration(name='Fe', values=1.79), 'Lig': Concentration(name='Lig', values=5.37), 'O2': Concentration(name='O2', values=187.5), 'DIC': Concentration(name='DIC', values=2370.0), 'DIC_ALT_CO2': Concentration(name='DIC_ALT_CO2', values=2370.0), 'ALK_ALT_CO2': Concentration(name='ALK_ALT_CO2', values=2310.0), 'DOC': Concentration(name='DOC', values=0.0001), 'DON': Concentration(name='DON', values=1.0), 'DOP': Concentration(name='DOP', values=0.1), 'DOPr': Concentration(name='DOPr', values=0.003), 'DONr': Concentration(name='DONr', values=0.8), 'DOCr': Concentration(name='DOCr', values=1e-06), 'zooC': Concentration(name='zooC', values=2.7), 'spChl': Concentration(name='spChl', values=1.35), 'spC': Concentration(name='spC', values=6.75), 'spP': Concentration(name='spP', values=0.045), 'spFe': Concentration(name='spFe', values=2.7e-05), 'spCaCO3': Concentration(name='spCaCO3', values=0.135), 'diatChl': Concentration(name='diatChl', values=0.135), 'diatC': Concentration(name='diatC', values=0.405), 'diatP': Concentration(name='diatP', values=0.03), 'diatFe': Concentration(name='diatFe', values=2.7e-06), 'diatSi': Concentration(name='diatSi', values=0.135), 'diazChl': Concentration(name='diazChl', values=0.015), 'diazC': Concentration(name='diazC', values=0.075), 'diazP': Concentration(name='diazP', values=0.015), 'diazFe': Concentration(name='diazFe', values=1.5e-06)})

For example, the default values for DIC and PO4 are 2370.0 mmol/m³ and 2.7 mmol/m³, respectively, as can be seen above.

Next, let’s create another release, but this time with fill_values = "zero" to explicitly set all unspecified tracer concentrations to zero.

[8]:
volume_release_norway_with_zero_fill = VolumeRelease(
    name="norway_release_zero_fill",
    lat=65.0,  # degree N
    lon=10,  # degree E
    depth=50,  # m
    times=times,
    volume_fluxes=volume_fluxes,
    tracer_concentrations=tracer_concentrations,
    fill_values="zero",
)

Below, you can see that missing tracer concentrations were correctly set to zero.

[9]:
volume_release_norway_with_zero_fill
[9]:
VolumeRelease(name='norway_release_zero_fill', lat=65.0, lon=10.0, depth=50.0, hsc=0.0, vsc=0.0, times=[datetime.datetime(2011, 1, 15, 12, 0), datetime.datetime(2011, 1, 15, 15, 0), datetime.datetime(2011, 1, 15, 18, 0), datetime.datetime(2011, 1, 19, 0, 0), datetime.datetime(2011, 1, 22, 6, 0), datetime.datetime(2011, 1, 22, 9, 0), datetime.datetime(2011, 1, 22, 12, 0)], time_interpolation=False, release_type=<ReleaseType.volume: 'volume'>, fill_values='zero', volume_fluxes=Flux(name='volume', values=[0.0, 100.0, 500.0, 1000.0, 500.0, 100.0, 0.0]), tracer_concentrations={'ALK': Concentration(name='ALK', values=[1900.0, 2100.0, 2100.0, 2100.0, 2100.0, 2100.0, 1900.0]), 'temp': Concentration(name='temp', values=20.0), 'salt': Concentration(name='salt', values=1.0), 'PO4': Concentration(name='PO4', values=0.0), 'NO3': Concentration(name='NO3', values=0.0), 'SiO3': Concentration(name='SiO3', values=0.0), 'NH4': Concentration(name='NH4', values=0.0), 'Fe': Concentration(name='Fe', values=0.0), 'Lig': Concentration(name='Lig', values=0.0), 'O2': Concentration(name='O2', values=0.0), 'DIC': Concentration(name='DIC', values=0.0), 'DIC_ALT_CO2': Concentration(name='DIC_ALT_CO2', values=0.0), 'ALK_ALT_CO2': Concentration(name='ALK_ALT_CO2', values=0.0), 'DOC': Concentration(name='DOC', values=0.0), 'DON': Concentration(name='DON', values=0.0), 'DOP': Concentration(name='DOP', values=0.0), 'DOPr': Concentration(name='DOPr', values=0.0), 'DONr': Concentration(name='DONr', values=0.0), 'DOCr': Concentration(name='DOCr', values=0.0), 'zooC': Concentration(name='zooC', values=0.0), 'spChl': Concentration(name='spChl', values=0.0), 'spC': Concentration(name='spC', values=0.0), 'spP': Concentration(name='spP', values=0.0), 'spFe': Concentration(name='spFe', values=0.0), 'spCaCO3': Concentration(name='spCaCO3', values=0.0), 'diatChl': Concentration(name='diatChl', values=0.0), 'diatC': Concentration(name='diatC', values=0.0), 'diatP': Concentration(name='diatP', values=0.0), 'diatFe': Concentration(name='diatFe', values=0.0), 'diatSi': Concentration(name='diatSi', values=0.0), 'diazChl': Concentration(name='diazChl', values=0.0), 'diazC': Concentration(name='diazC', values=0.0), 'diazP': Concentration(name='diazP', values=0.0), 'diazFe': Concentration(name='diazFe', values=0.0)})

Note: Later, we’ll cover how to visualize release locations, volume fluxes, and tracer concentrations (including default fill values), once a CDRForcing object has been created.

Defining a TracerPerturbation#

This section covers how to configure and use the TracerPerturbation class to represent injections of tracers without water into a ROMS simulation.

In addition to the location parameters, a TracerPerturbation has the key field:

  • tracer_fluxes

Both can be specified as either constant or time-varying.

[10]:
from roms_tools import TracerPerturbation

Call .get_metadata() to view the expected units for each tracer flux.

[11]:
TracerPerturbation.get_metadata()
[11]:
temp salt PO4 NO3 SiO3 NH4 Fe Lig O2 DIC DIC_ALT_CO2 ALK ALK_ALT_CO2 DOC DON DOP DOPr DONr DOCr zooC spChl spC spP spFe spCaCO3 diatChl diatC diatP diatFe diatSi diazChl diazC diazP diazFe
units degrees Celsius/s PSU/s mmol/s mmol/s mmol/s mmol/s mmol/s mmol/s mmol/s mmol/s meq/s meq/s meq/s mmol/s mmol/s mmol/s mmol/s mmol/s mmol/s mmol/s mg/s mmol/s mmol/s mmol/s mmol/s mg/s mmol/s mmol/s mmol/s mmol/s mg/s mmol/s mmol/s mmol/s
long_name potential temperature salinity dissolved inorganic phosphate dissolved inorganic nitrate dissolved inorganic silicate dissolved ammonia dissolved inorganic iron iron binding ligand dissolved oxygen dissolved inorganic carbon dissolved inorganic carbon, alternative CO2 alkalinity alkalinity, alternative CO2 dissolved organic carbon dissolved organic nitrogen dissolved organic phosphorus refractory dissolved organic phosphorus refractory dissolved organic nitrogen refractory dissolved organic carbon zooplankton carbon small phytoplankton chlorophyll small phytoplankton carbon small phytoplankton phosphorous small phytoplankton iron small phytoplankton CaCO3 diatom chloropyll diatom carbon diatom phosphorus diatom iron diatom silicate diazotroph chloropyll diazotroph carbon diazotroph phosphorus diazotroph iron

Constant tracer flux#

Let’s start by defining a release near Iceland that has a Gaussian distribution (with standard deviations of 100km in the horizontal and 50m in the vertical) and a constant alkalinity flux:

  • Alkalinity flux: 2,000,000 meq/s

This ocean alkalinity enhancement (OAE) experiment is equivalent to the VolumeRelease example above, where 2000 meq/m³ of alkalinity was injected with a 1000 m³/s volume flux. However, in this case, no water is added, only the tracer. As before, this single flux value is applied consistently throughout the entire ROMS simulation.

[12]:
constant_oae_iceland = TracerPerturbation(
    name="iceland_oae",
    lat=65.0,  # degree N
    lon=-10,  # degree E
    depth=100,  # m
    hsc=100000,  # m
    vsc=50,  # m
    tracer_fluxes={"ALK": 2 * 10**6},  # meq/s
)

We can also define a direct ocean removal (DOR) experiment as follows.

[13]:
constant_dor_iceland = TracerPerturbation(
    name="iceland_dor",
    lat=65.0,  # degree N
    lon=-25,  # degree E
    depth=100,  # m
    hsc=100000,  # m
    vsc=50,  # m
    tracer_fluxes={"DIC": - 2 * 10**6},  # mmol/s
)

Time-varying tracer fluxes#

To define a time-varying release, specify the times parameter with explicit time points for tracer fluxes.

In the example below, the alkalinity flux varies over time (as list matching times length).

Note

Intermediate tracer flux values between the specified times are linearly interpolated when the CDRForcing object is constructed later.

[14]:
times_trcr = [
    datetime(2011, 1, 15, 12, 0),
    datetime(2011, 1, 15, 15, 0),
    datetime(2011, 1, 15, 18, 0),
    datetime(2011, 1, 19, 0, 0),
    datetime(2011, 1, 22, 6, 0),
    datetime(2011, 1, 22, 9, 0),
    datetime(2011, 1, 22, 12, 0),
]  # 7 entries
tracer_fluxes = {
    "ALK": [
        0.0,
        2.0 * 10**6,  # meq/s
        3.0 * 10**6,  # meq/s
        4.0 * 10**6,  # meq/s
        3.0 * 10**6,  # meq/s
        2.0 * 10**6,  # meq/s
        0.0,
    ],  # 7 entries
}

Given these tracer fluxes, we now define a tracer perturbation as a Gaussian with a standard deviation of 150km in the horizontal and 100m in the vertical.

[15]:
tracer_perturbation_greenland = TracerPerturbation(
    name="greenland_release",
    lat=70.0,  # degree N
    lon=-20.0,  # degree E
    depth=100,  # m
    hsc=150000,  # m
    vsc=100,  # m
    times=times_trcr,
    tracer_fluxes=tracer_fluxes,
)

Fill values are always zero#

For TracerPerturbation, any tracer flux not explicitly specified is automatically set to zero, as this object represents a perturbation rather than a complete tracer field. For that reason, TracerPerturbation does not have a fill_values parameter.

We confirm this automatic zero-filling behavior in the example below.

[16]:
tracer_perturbation_greenland
[16]:
TracerPerturbation(name='greenland_release', lat=70.0, lon=-20.0, depth=100.0, hsc=150000.0, vsc=100.0, times=[datetime.datetime(2011, 1, 15, 12, 0), datetime.datetime(2011, 1, 15, 15, 0), datetime.datetime(2011, 1, 15, 18, 0), datetime.datetime(2011, 1, 19, 0, 0), datetime.datetime(2011, 1, 22, 6, 0), datetime.datetime(2011, 1, 22, 9, 0), datetime.datetime(2011, 1, 22, 12, 0)], time_interpolation=False, release_type=<ReleaseType.tracer_perturbation: 'tracer_perturbation'>, tracer_fluxes={'ALK': Flux(name='ALK', values=[0.0, 2000000.0, 3000000.0, 4000000.0, 3000000.0, 2000000.0, 0.0]), 'temp': Flux(name='temp', values=0.0), 'salt': Flux(name='salt', values=0.0), 'PO4': Flux(name='PO4', values=0.0), 'NO3': Flux(name='NO3', values=0.0), 'SiO3': Flux(name='SiO3', values=0.0), 'NH4': Flux(name='NH4', values=0.0), 'Fe': Flux(name='Fe', values=0.0), 'Lig': Flux(name='Lig', values=0.0), 'O2': Flux(name='O2', values=0.0), 'DIC': Flux(name='DIC', values=0.0), 'DIC_ALT_CO2': Flux(name='DIC_ALT_CO2', values=0.0), 'ALK_ALT_CO2': Flux(name='ALK_ALT_CO2', values=0.0), 'DOC': Flux(name='DOC', values=0.0), 'DON': Flux(name='DON', values=0.0), 'DOP': Flux(name='DOP', values=0.0), 'DOPr': Flux(name='DOPr', values=0.0), 'DONr': Flux(name='DONr', values=0.0), 'DOCr': Flux(name='DOCr', values=0.0), 'zooC': Flux(name='zooC', values=0.0), 'spChl': Flux(name='spChl', values=0.0), 'spC': Flux(name='spC', values=0.0), 'spP': Flux(name='spP', values=0.0), 'spFe': Flux(name='spFe', values=0.0), 'spCaCO3': Flux(name='spCaCO3', values=0.0), 'diatChl': Flux(name='diatChl', values=0.0), 'diatC': Flux(name='diatC', values=0.0), 'diatP': Flux(name='diatP', values=0.0), 'diatFe': Flux(name='diatFe', values=0.0), 'diatSi': Flux(name='diatSi', values=0.0), 'diazChl': Flux(name='diazChl', values=0.0), 'diazC': Flux(name='diazC', values=0.0), 'diazP': Flux(name='diazP', values=0.0), 'diazFe': Flux(name='diazFe', values=0.0)})

CDR Forcing#

The CDR Forcing object links one or multiple releases to the underlying ROMS simulation. It requires the following inputs:

  1. One or multiple releases, all of the same type (either all VolumeRelease or all TracerPerturbation)

  2. The model grid (optional but strongly recommended)

  3. The simulation start and end dates (required)

Notes

  • Model Grid: Although optional, providing the model grid is highly recommended. Without it, important validation checks, such as verifying whether release locations fall outside the grid domain or on land, cannot be performed. Additionally, plotting release locations requires the model grid to be provided.

  • Simulation Start and End Dates: These are necessary for two reasons:

    • To ensure that the release window does not fall outside the simulation window.

    • ROMS requires forcing data for the entire simulation period. If a release’s specified times do not fully cover the simulation period, ROMS-Tools will extend the release data to the simulation endpoints using a default method (details provided in this section).

Let’s create our CDR forcings for the following grid spanning the Nordic Seas.

[17]:
from roms_tools import Grid
[18]:
grid = Grid(
    nx=250,
    ny=250,
    size_x=2500,
    size_y=2500,
    center_lon=-15,
    center_lat=65,
    rot=-30,
    N=100,
    topography_source={
        "name": "SRTM15",
        "path": "/anvil/projects/x-ees250129/Datasets/SRTM15/SRTM15_V2.6.nc",
    },
)
[19]:
grid.plot()
_images/cdr_forcing_36_0.png

Next, we specify the start and end times of the underlying ROMS simulation.

[20]:
simulation_start_time = datetime(2010, 1, 1)
simulation_end_time = datetime(2012, 12, 31)

Creating the CDRForcing#

[21]:
simulation_end_time-simulation_start_time
[21]:
datetime.timedelta(days=1095)
[22]:
from roms_tools import CDRForcing

Let’s first create a CDRForcing that consists of all the VolumeReleases that we defined above.

[23]:
cdr_forcing_with_volume_releases = CDRForcing(
    grid=grid,
    start_time=simulation_start_time,
    end_time=simulation_end_time,
    model_reference_date=datetime(2000, 1, 1), # this is the default
    releases=[
        constant_volume_release_iceland,
        volume_release_greenland,
        volume_release_norway_with_zero_fill,
    ],
)

Similarly, we can create a CDRForcing that consists of all the TracerPerturbations that we defined above.

[24]:
cdr_forcing_with_tracer_perturbations = CDRForcing(
    grid=grid,
    start_time=simulation_start_time,
    end_time=simulation_end_time,
    model_reference_date=datetime(2000, 1, 1), # this is the default
    releases=[
        constant_oae_iceland,
        constant_dor_iceland,
        tracer_perturbation_greenland,
    ],
)

The .ds attribute of each CDRForcing object holds an xarray Dataset with the release information. This dataset can eventually be saved to a NetCDF file, providing the ROMS input file.

[25]:
cdr_forcing_with_volume_releases.ds
[25]:
<xarray.Dataset> Size: 17kB
Dimensions:           (time: 9, ncdr: 3, ntracers: 34)
Coordinates:
  * time              (time) datetime64[ns] 72B 2010-01-01 ... 2012-12-31
    release_name      (ncdr) <U24 288B 'iceland_release' ... 'norway_release_...
    tracer_name       (ntracers) <U11 1kB 'temp' 'salt' ... 'diazP' 'diazFe'
    tracer_unit       (ntracers) <U15 2kB 'degrees Celsius' 'PSU' ... 'mmol/m^3'
    tracer_long_name  (ntracers) <U43 6kB 'potential temperature' ... 'diazot...
Dimensions without coordinates: ncdr, ntracers
Data variables:
    cdr_time          (time) float64 72B 3.653e+03 4.032e+03 ... 4.748e+03
    cdr_lon           (ncdr) float64 24B -10.0 -20.0 10.0
    cdr_lat           (ncdr) float64 24B 65.0 70.0 65.0
    cdr_dep           (ncdr) float64 24B 100.0 100.0 50.0
    cdr_hsc           (ncdr) float64 24B 0.0 0.0 0.0
    cdr_vsc           (ncdr) float64 24B 0.0 0.0 0.0
    cdr_interp        (ncdr) bool 3B False False False
    cdr_volume        (time, ncdr) float64 216B 1e+03 0.0 0.0 ... 1e+03 0.0 0.0
    cdr_tracer        (time, ntracers, ncdr) float64 7kB 20.0 20.0 ... 0.0

The dataset above contains 3 releases, as indicated by the ncdr dimension.

In contrast, the next dataset contains only 2 releases, as expected.

[26]:
cdr_forcing_with_tracer_perturbations.ds
[26]:
<xarray.Dataset> Size: 17kB
Dimensions:           (time: 9, ncdr: 3, ntracers: 34)
Coordinates:
  * time              (time) datetime64[ns] 72B 2010-01-01 ... 2012-12-31
    release_name      (ncdr) <U17 204B 'iceland_oae' ... 'greenland_release'
    tracer_name       (ntracers) <U11 1kB 'temp' 'salt' ... 'diazP' 'diazFe'
    tracer_unit       (ntracers) <U17 2kB 'degrees Celsius/s' ... 'mmol/s'
    tracer_long_name  (ntracers) <U43 6kB 'potential temperature' ... 'diazot...
Dimensions without coordinates: ncdr, ntracers
Data variables:
    cdr_time          (time) float64 72B 3.653e+03 4.032e+03 ... 4.748e+03
    cdr_lon           (ncdr) float64 24B -10.0 -25.0 -20.0
    cdr_lat           (ncdr) float64 24B 65.0 65.0 70.0
    cdr_dep           (ncdr) float64 24B 100.0 100.0 100.0
    cdr_hsc           (ncdr) float64 24B 1e+05 1e+05 1.5e+05
    cdr_vsc           (ncdr) float64 24B 50.0 50.0 100.0
    cdr_interp        (ncdr) bool 3B False False False
    cdr_trcflx        (time, ntracers, ncdr) float64 7kB 0.0 0.0 0.0 ... 0.0 0.0

Plotting the Release Locations and Distributions#

We now continue with visualizing the release locations and distributions. First, we will create a bird’s-eye view of the release location centers.

[27]:
cdr_forcing_with_volume_releases.plot_locations()  # By default, this plots all available releases (but max 20).
_images/cdr_forcing_51_0.png

We can also restrict the plot to display only the releases of interest by specifying them in a list via the release_names parameter.

[28]:
cdr_forcing_with_volume_releases.plot_locations(
    release_names=["iceland_release", "norway_release_zero_fill"]
)
_images/cdr_forcing_53_0.png
[29]:
cdr_forcing_with_tracer_perturbations.plot_locations()
_images/cdr_forcing_54_0.png

Next, we plot the release distributions from a top and side view. Note that we can only plot one release at a time in this view, as the latitude and longitude section to be visualized depends on the specific location of the release itself.

[30]:
cdr_forcing_with_volume_releases.plot_distribution(release_name="greenland_release")
_images/cdr_forcing_56_0.png

The VolumeRelease we visualized in the plot above is a point source. Next, let’s visualize our tracer perturbations, which are released as Gaussian distributions.

[31]:
cdr_forcing_with_tracer_perturbations.plot_distribution(
    release_name="greenland_release"
)
_images/cdr_forcing_58_0.png

If the black cross at the release center bothers you, you can remove it by setting mark_release_center = False, as shown in the next plot.

[32]:
cdr_forcing_with_tracer_perturbations.plot_distribution(
    release_name="greenland_release", mark_release_center=False
)
_images/cdr_forcing_60_0.png
[33]:
cdr_forcing_with_tracer_perturbations.plot_distribution(release_name="iceland_oae")
_images/cdr_forcing_61_0.png

Plotting Volume Fluxes and Tracer Concentrations#

This section applies only to CDRForcing objects that contain releases of type VolumeRelease. These releases are associated with both volume fluxes and tracer concentrations, which we will visualize next.

[34]:
cdr_forcing_with_volume_releases.plot_volume_flux()
_images/cdr_forcing_63_0.png

You can see that the iceland_release applies a constant volume flux throughout the entire simulation period, while the other two releases have time-varying volume fluxes, just as we designed them earlier.

If desired, you can also limit the plot to specific releases using the release_names parameter.

[35]:
cdr_forcing_with_volume_releases.plot_volume_flux(
    release_names=["iceland_release", "greenland_release"]
)
_images/cdr_forcing_65_0.png

We can also zoom into the specific time window where the greenland_release occurs to better visualize the time-varying behavior of the volume flux.

[36]:
cdr_forcing_with_volume_releases.plot_volume_flux(
    release_names=["iceland_release", "greenland_release"],
    start=datetime(2011, 1, 15),
    end=datetime(2011, 1, 23),
)
_images/cdr_forcing_67_0.png

Next, we plot the alkalinity concentration.

[37]:
cdr_forcing_with_volume_releases.plot_tracer_concentration(
    tracer_name="ALK", release_names=["iceland_release", "greenland_release"]
)
_images/cdr_forcing_69_0.png

Again, the iceland_release uses an alkalinity concentration that is constant in time, while the greenland_release has a time-varying alkalinity concentration.

[38]:
cdr_forcing_with_volume_releases.plot_tracer_concentration(
    tracer_name="ALK",
    release_names=["iceland_release", "greenland_release"],
    start=datetime(2011, 1, 15),
    end=datetime(2011, 1, 23),
)
_images/cdr_forcing_71_0.png

Finally, we plot the DIC concentration to visualize the effect of the default fill versus the zero fill.

[39]:
cdr_forcing_with_volume_releases.plot_tracer_concentration(
    tracer_name="DIC", release_names=["greenland_release", "norway_release_zero_fill"]
)
_images/cdr_forcing_73_0.png

Plotting Tracer Fluxes#

This section applies only to CDRForcing objects that contain releases of type TracerPerturbation. These releases are associated with tracer fluxes, which we will visualize next. The plot_tracer_flux method works similarly as the plot_volume_flux and plot_tracer_concentration methods above.

[40]:
cdr_forcing_with_tracer_perturbations.plot_tracer_flux(tracer_name="ALK")
_images/cdr_forcing_75_0.png
[41]:
cdr_forcing_with_tracer_perturbations.plot_tracer_flux(
    tracer_name="ALK", start=datetime(2011, 1, 15), end=datetime(2011, 1, 23)
)
_images/cdr_forcing_76_0.png
[42]:
cdr_forcing_with_tracer_perturbations.plot_tracer_flux(tracer_name="DIC")
_images/cdr_forcing_77_0.png

Linear Interpolation#

So far, all of our volume flux and tracer concentrations have been shown as step function, where the value stays constant until a new value is prescribed. This is because CDRForcing sets time_interpolation to False by default. If we want to interpolate between points, we can set it to True.

Let’s remake our previous example volume_release_greenland, but setting time_interpolation=True.

[43]:
volume_release_greenland_interpolation = VolumeRelease(
    name="greenland_release",
    lat=70.0,  # degree N
    lon=-20.0,  # degree E
    depth=100,  # m
    times=volume_release_greenland.times,
    volume_fluxes=volume_release_greenland.volume_fluxes.values,
    tracer_concentrations=volume_release_greenland.tracer_concentrations,
    time_interpolation=True,
)

cdr_forcing_with_volume_release_interpolation = CDRForcing(
    grid=grid,
    start_time=simulation_start_time,
    end_time=simulation_end_time,
    model_reference_date=datetime(2000, 1, 1), # this is the default
    releases=[
        volume_release_greenland_interpolation,
    ],
)
[44]:
cdr_forcing_with_volume_release_interpolation.plot_volume_flux(
    release_names=["greenland_release"],
    start=datetime(2011, 1, 15),
    end=datetime(2011, 1, 23),
)
_images/cdr_forcing_81_0.png

Notice how there is a tail between the start time (datetime(2010, 1, 1)) and our first assigned date (datetime(2011, 1, 15, 12, 0)). This is due to the automatic extrapolation that ROMS-Tools performs.

Automatic Extrapolation to Simulation Endpoints#

Important

ROMS requires volume fluxes and tracer concentrations for the entire simulation period. If the user does not specify the simulation’s start and end points in their time series, ROMS-Tools will apply the following defaults:

  • Volume and tracer fluxes are set to 0 at both the start and end times.

  • Tracer concentrations at the start and end times are set to the values from the closest available time stamps.

Let’s examine how these rules play out in practice by revisiting our previous VolumeRelease examples: volume_release_greenland_interpolation. This release was defined with the following times, volume fluxes, and alkalinity concentrations (where the endpoints have been filled in when we built cdr_forcing_with_volume_release_interpolation).

[45]:
volume_release_greenland_interpolation.times
[45]:
[datetime.datetime(2010, 1, 1, 0, 0),
 datetime.datetime(2011, 1, 15, 12, 0),
 datetime.datetime(2011, 1, 15, 15, 0),
 datetime.datetime(2011, 1, 15, 18, 0),
 datetime.datetime(2011, 1, 19, 0, 0),
 datetime.datetime(2011, 1, 22, 6, 0),
 datetime.datetime(2011, 1, 22, 9, 0),
 datetime.datetime(2011, 1, 22, 12, 0),
 datetime.datetime(2012, 12, 31, 0, 0)]
[46]:
volume_release_greenland_interpolation.volume_fluxes.values
[46]:
[0.0, 0.0, 100.0, 500.0, 1000.0, 500.0, 100.0, 0.0, 0.0]
[47]:
volume_release_greenland_interpolation.tracer_concentrations["ALK"].values
[47]:
[1900.0, 1900.0, 2100.0, 2100.0, 2100.0, 2100.0, 2100.0, 1900.0, 1900.0]

In the next example, we define a very similar release as before, but we omit the first two and the last two timestamps from the time series.

[48]:
times = volume_release_greenland_interpolation.times[2:-2]
times
[48]:
[datetime.datetime(2011, 1, 15, 15, 0),
 datetime.datetime(2011, 1, 15, 18, 0),
 datetime.datetime(2011, 1, 19, 0, 0),
 datetime.datetime(2011, 1, 22, 6, 0),
 datetime.datetime(2011, 1, 22, 9, 0)]
[49]:
volume_fluxes = volume_release_greenland_interpolation.volume_fluxes.values[2:-2]
volume_fluxes
[49]:
[100.0, 500.0, 1000.0, 500.0, 100.0]
[50]:
alk_concentration = volume_release_greenland_interpolation.tracer_concentrations["ALK"].values[2:-2]
alk_concentration
[50]:
[2100.0, 2100.0, 2100.0, 2100.0, 2100.0]
[51]:
volume_release_greenland_interpolation_truncated = VolumeRelease(
    name="greenland_release_cut_short",
    lat=volume_release_greenland.lat,
    lon=volume_release_greenland.lon,
    depth=volume_release_greenland.depth,
    times=times,
    volume_fluxes=volume_fluxes,
    tracer_concentrations={"ALK": alk_concentration},
    time_interpolation=True,
)
[52]:
volume_release_greenland_interpolation_truncated.volume_fluxes.values
[52]:
[100.0, 500.0, 1000.0, 500.0, 100.0]
[53]:
cdr_forcing = CDRForcing(
    grid=grid,
    start_time=simulation_start_time,
    end_time=simulation_end_time,
    releases=[volume_release_greenland_interpolation, volume_release_greenland_interpolation_truncated],
)

Let’s now compare the time series of volume flux and alkalinity concentration for the two releases.

[54]:
cdr_forcing.plot_volume_flux(start=datetime(2011, 1, 15), end=datetime(2011, 1, 23))
_images/cdr_forcing_95_0.png

If we zoom out, we can see how the tails are handled.

[55]:
cdr_forcing.plot_volume_flux()
_images/cdr_forcing_97_0.png

We see that when time_interpolation is turned on, not assigning values to the start and end points on the simulation will result in ROMS-Tools extrapolating to 0 for each. Explicitly prescribing times when the volume and tracer fluxes avoids this tail of additional fluxes.

To re-iterate, the above plot shows the effect of choosing:

  • volume_fluxes = [0.0, 100.0, 500.0, 1000.0, 500.0, 100.0, 0.0] (blue line) vs.

  • volume_fluxes = [100.0, 500.0, 1000.0, 500.0, 100.0] (orange line)

The first choice explicitly defines when to shut off the volume flux.
The second choice does not define this, so ROMS-Tools assumes the flux is only shut off at the simulation endpoints and linearly interpolates in between.
[56]:
cdr_forcing.plot_tracer_concentration(tracer_name="ALK")
_images/cdr_forcing_100_0.png

To re-iterate, the above plot shows the effect of choosing:

  • tracer_concentrations["ALK"] = [1900.0, 2100.0, 2100.0, 2100.0, 2100.0, 2100.0, 1900.0] (blue line) vs.

  • tracer_concentrations["ALK"] = [2100.0, 2100.0, 2100.0, 2100.0, 2100.0] (orange line)

In both cases, ROMS-Tools extrapolates the endpoints of the provided time series to the simulation endpoints.

Total Tracer Release Accounting#

In marine CDR experiments, it is essential to ensure that the ROMS simulation matches the intended tracer inputs, e.g., the total amount of alkalinity added or DIC removed. To achieve this, ROMS-Tools computes the cumulative tracer release for each release over the simulation period via the .compute_total_cdr_source() method.

The total amount of tracer released or removed depends on the time discretization used in the ROMS simulation. To reproduce exactly what ROMS will do, ROMS-Tools reconstructs the ROMS time stamps. This requires:

  • The simulation start and end times, already provided when instantiating the CDRForcing object (start_time and end_time). Make sure that these exactly match the actual start and end time of the simulation.

  • The model time step dt, which defines the temporal resolution of the integration.

The output is a pandas DataFrame with releases as rows and tracers as columns, showing the cumulative mass of each tracer released. Different choices of dt may produce slightly different totals due to discretization.

[57]:
dt0 = 150 # ROMS time step in seconds
df0_vr = cdr_forcing_with_volume_releases.compute_total_cdr_source(dt=dt0)
df0_vr
[57]:
ALK PO4 NO3 SiO3 NH4 Fe Lig O2 DIC DIC_ALT_CO2 ALK_ALT_CO2 DOC DON DOP DOPr DONr DOCr zooC spChl spC spP spFe spCaCO3 diatChl diatC diatP diatFe diatSi diazChl diazC diazP diazFe
units meq mmol mmol mmol mmol mmol mmol mmol mmol meq meq mmol mmol mmol mmol mmol mmol mmol mg mmol mmol mmol mmol mg mmol mmol mmol mmol mg mmol mmol mmol
iceland_release 189216000000000.0 255441600000.0 2289513600000.0 1248825600000.0 208137600000.0 169348320000.0 508044960000.0 17739000000000.0 224220960000000.0 224220960000000.0 218544480000000.0 9460800.0 94608000000.0 9460800000.0 283824000.0 75686400000.0 94608.0 255441600000.0 127720800000.0 638604000000.0 4257360000.0 2554416.0 12772080000.0 12772080000.0 38316240000.0 2838240000.0 255441.6 12772080000.0 1419120000.0 7095600000.0 1419120000.0 141912.0
greenland_release 900396000000.0 1157652000.0 10375992000.0 5659632000.0 943272000.0 767480400.0 2302441200.0 80392500000.0 1016161200000.0 1016161200000.0 990435600000.0 42876.0 428760000.0 42876000.0 1286280.0 343008000.0 428.76 1157652000.0 578826000.0 2894130000.0 19294200.0 11576.52 57882600.0 57882600.0 173647800.0 12862800.0 1157.652 57882600.0 6431400.0 32157000.0 6431400.0 643.14
norway_release_zero_fill 900396000000.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

We can do a similar analysis for our released tracer perturbations.

[58]:
df0_tp = cdr_forcing_with_tracer_perturbations.compute_total_cdr_source(dt=150)
df0_tp
[58]:
ALK PO4 NO3 SiO3 NH4 Fe Lig O2 DIC DIC_ALT_CO2 ALK_ALT_CO2 DOC DON DOP DOPr DONr DOCr zooC spChl spC spP spFe spCaCO3 diatChl diatC diatP diatFe diatSi diazChl diazC diazP diazFe
units meq mmol mmol mmol mmol mmol mmol mmol mmol meq meq mmol mmol mmol mmol mmol mmol mmol mg mmol mmol mmol mmol mg mmol mmol mmol mmol mg mmol mmol mmol
iceland_oae 189216000000000.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
iceland_dor 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -189216000000000.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
greenland_release 2041200000000.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

Saving as NetCDF or YAML File#

We can now save our CDR forcing data as a NetCDF file using the .save method. This file will include the dataset stored in .ds. The resulting NetCDF file can then be used as input for ROMS simulations.

In this example, we focus on the CDR forcing built from VolumeRelease objects, but the same saving procedure applies to CDR forcing created from TracerPerturbation objects.

[59]:
filepath = "my_cdr_forcing.nc"
[60]:
cdr_forcing_with_volume_releases.save(filepath=filepath)
2026-05-11 19:40:40 - INFO - Writing the following NetCDF files:
my_cdr_forcing.nc
[60]:
[PosixPath('my_cdr_forcing.nc')]

We can also export the CDR forcing parameters and their associated release information to a YAML file.

[61]:
yaml_filepath = "my_cdr_forcing.yaml"
[62]:
cdr_forcing_with_volume_releases.to_yaml(yaml_filepath)

This is the YAML file that was created.

[63]:
# Open and read the YAML file
with open(yaml_filepath, "r") as file:
    file_contents = file.read()

# Print the contents
print(file_contents)
---
roms_tools_version: 3.6.1.dev31+g34326e51e
---
Grid:
  nx: 250
  ny: 250
  size_x: 2500
  size_y: 2500
  center_lon: -15
  center_lat: 65
  rot: -30
  N: 100
  theta_s: 5.0
  theta_b: 2.0
  hc: 300.0
  topography_source:
    name: SRTM15
    path: /anvil/projects/x-ees250129/Datasets/SRTM15/SRTM15_V2.6.nc
  mask_shapefile: null
  close_narrow_channels: false
  hmin: 5.0
  filename: null
CDRForcing:
  start_time: '2010-01-01T00:00:00'
  end_time: '2012-12-31T00:00:00'
  model_reference_date: '2000-01-01T00:00:00'
  releases:
  - name: iceland_release
    lat: 65.0
    lon: -10.0
    depth: 100.0
    hsc: 0.0
    vsc: 0.0
    times:
    - 2010-01-01 00:00:00
    - 2012-12-31 00:00:00
    time_interpolation: false
    release_type: volume
    fill_values: auto
    volume_fluxes:
    - 1000.0
    - 1000.0
    tracer_concentrations:
      temp:
      - 20.0
      - 20.0
      salt:
      - 1.0
      - 1.0
      ALK:
      - 2000.0
      - 2000.0
      PO4:
      - 2.7
      - 2.7
      NO3:
      - 24.2
      - 24.2
      SiO3:
      - 13.2
      - 13.2
      NH4:
      - 2.2
      - 2.2
      Fe:
      - 1.79
      - 1.79
      Lig:
      - 5.37
      - 5.37
      O2:
      - 187.5
      - 187.5
      DIC:
      - 2370.0
      - 2370.0
      DIC_ALT_CO2:
      - 2370.0
      - 2370.0
      ALK_ALT_CO2:
      - 2310.0
      - 2310.0
      DOC:
      - 0.0001
      - 0.0001
      DON:
      - 1.0
      - 1.0
      DOP:
      - 0.1
      - 0.1
      DOPr:
      - 0.003
      - 0.003
      DONr:
      - 0.8
      - 0.8
      DOCr:
      - 1.0e-06
      - 1.0e-06
      zooC:
      - 2.7
      - 2.7
      spChl:
      - 1.35
      - 1.35
      spC:
      - 6.75
      - 6.75
      spP:
      - 0.045
      - 0.045
      spFe:
      - 2.7e-05
      - 2.7e-05
      spCaCO3:
      - 0.135
      - 0.135
      diatChl:
      - 0.135
      - 0.135
      diatC:
      - 0.405
      - 0.405
      diatP:
      - 0.03
      - 0.03
      diatFe:
      - 2.7e-06
      - 2.7e-06
      diatSi:
      - 0.135
      - 0.135
      diazChl:
      - 0.015
      - 0.015
      diazC:
      - 0.075
      - 0.075
      diazP:
      - 0.015
      - 0.015
      diazFe:
      - 1.5e-06
      - 1.5e-06
  - name: greenland_release
    lat: 70.0
    lon: -20.0
    depth: 100.0
    hsc: 0.0
    vsc: 0.0
    times:
    - 2010-01-01 00:00:00
    - 2011-01-15 12:00:00
    - 2011-01-15 15:00:00
    - 2011-01-15 18:00:00
    - 2011-01-19 00:00:00
    - 2011-01-22 06:00:00
    - 2011-01-22 09:00:00
    - 2011-01-22 12:00:00
    - 2012-12-31 00:00:00
    time_interpolation: false
    release_type: volume
    fill_values: auto
    volume_fluxes:
    - 0.0
    - 0.0
    - 100.0
    - 500.0
    - 1000.0
    - 500.0
    - 100.0
    - 0.0
    - 0.0
    tracer_concentrations:
      ALK:
      - 1900.0
      - 1900.0
      - 2100.0
      - 2100.0
      - 2100.0
      - 2100.0
      - 2100.0
      - 1900.0
      - 1900.0
      temp:
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      salt:
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      PO4:
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      NO3:
      - 24.2
      - 24.2
      - 24.2
      - 24.2
      - 24.2
      - 24.2
      - 24.2
      - 24.2
      - 24.2
      SiO3:
      - 13.2
      - 13.2
      - 13.2
      - 13.2
      - 13.2
      - 13.2
      - 13.2
      - 13.2
      - 13.2
      NH4:
      - 2.2
      - 2.2
      - 2.2
      - 2.2
      - 2.2
      - 2.2
      - 2.2
      - 2.2
      - 2.2
      Fe:
      - 1.79
      - 1.79
      - 1.79
      - 1.79
      - 1.79
      - 1.79
      - 1.79
      - 1.79
      - 1.79
      Lig:
      - 5.37
      - 5.37
      - 5.37
      - 5.37
      - 5.37
      - 5.37
      - 5.37
      - 5.37
      - 5.37
      O2:
      - 187.5
      - 187.5
      - 187.5
      - 187.5
      - 187.5
      - 187.5
      - 187.5
      - 187.5
      - 187.5
      DIC:
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      DIC_ALT_CO2:
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      - 2370.0
      ALK_ALT_CO2:
      - 2310.0
      - 2310.0
      - 2310.0
      - 2310.0
      - 2310.0
      - 2310.0
      - 2310.0
      - 2310.0
      - 2310.0
      DOC:
      - 0.0001
      - 0.0001
      - 0.0001
      - 0.0001
      - 0.0001
      - 0.0001
      - 0.0001
      - 0.0001
      - 0.0001
      DON:
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      DOP:
      - 0.1
      - 0.1
      - 0.1
      - 0.1
      - 0.1
      - 0.1
      - 0.1
      - 0.1
      - 0.1
      DOPr:
      - 0.003
      - 0.003
      - 0.003
      - 0.003
      - 0.003
      - 0.003
      - 0.003
      - 0.003
      - 0.003
      DONr:
      - 0.8
      - 0.8
      - 0.8
      - 0.8
      - 0.8
      - 0.8
      - 0.8
      - 0.8
      - 0.8
      DOCr:
      - 1.0e-06
      - 1.0e-06
      - 1.0e-06
      - 1.0e-06
      - 1.0e-06
      - 1.0e-06
      - 1.0e-06
      - 1.0e-06
      - 1.0e-06
      zooC:
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      - 2.7
      spChl:
      - 1.35
      - 1.35
      - 1.35
      - 1.35
      - 1.35
      - 1.35
      - 1.35
      - 1.35
      - 1.35
      spC:
      - 6.75
      - 6.75
      - 6.75
      - 6.75
      - 6.75
      - 6.75
      - 6.75
      - 6.75
      - 6.75
      spP:
      - 0.045
      - 0.045
      - 0.045
      - 0.045
      - 0.045
      - 0.045
      - 0.045
      - 0.045
      - 0.045
      spFe:
      - 2.7e-05
      - 2.7e-05
      - 2.7e-05
      - 2.7e-05
      - 2.7e-05
      - 2.7e-05
      - 2.7e-05
      - 2.7e-05
      - 2.7e-05
      spCaCO3:
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      diatChl:
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      diatC:
      - 0.405
      - 0.405
      - 0.405
      - 0.405
      - 0.405
      - 0.405
      - 0.405
      - 0.405
      - 0.405
      diatP:
      - 0.03
      - 0.03
      - 0.03
      - 0.03
      - 0.03
      - 0.03
      - 0.03
      - 0.03
      - 0.03
      diatFe:
      - 2.7e-06
      - 2.7e-06
      - 2.7e-06
      - 2.7e-06
      - 2.7e-06
      - 2.7e-06
      - 2.7e-06
      - 2.7e-06
      - 2.7e-06
      diatSi:
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      - 0.135
      diazChl:
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      diazC:
      - 0.075
      - 0.075
      - 0.075
      - 0.075
      - 0.075
      - 0.075
      - 0.075
      - 0.075
      - 0.075
      diazP:
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      - 0.015
      diazFe:
      - 1.5e-06
      - 1.5e-06
      - 1.5e-06
      - 1.5e-06
      - 1.5e-06
      - 1.5e-06
      - 1.5e-06
      - 1.5e-06
      - 1.5e-06
  - name: norway_release_zero_fill
    lat: 65.0
    lon: 10.0
    depth: 50.0
    hsc: 0.0
    vsc: 0.0
    times:
    - 2010-01-01 00:00:00
    - 2011-01-15 12:00:00
    - 2011-01-15 15:00:00
    - 2011-01-15 18:00:00
    - 2011-01-19 00:00:00
    - 2011-01-22 06:00:00
    - 2011-01-22 09:00:00
    - 2011-01-22 12:00:00
    - 2012-12-31 00:00:00
    time_interpolation: false
    release_type: volume
    fill_values: zero
    volume_fluxes:
    - 0.0
    - 0.0
    - 100.0
    - 500.0
    - 1000.0
    - 500.0
    - 100.0
    - 0.0
    - 0.0
    tracer_concentrations:
      ALK:
      - 1900.0
      - 1900.0
      - 2100.0
      - 2100.0
      - 2100.0
      - 2100.0
      - 2100.0
      - 1900.0
      - 1900.0
      temp:
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      - 20.0
      salt:
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      PO4:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      NO3:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      SiO3:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      NH4:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      Fe:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      Lig:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      O2:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      DIC:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      DIC_ALT_CO2:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      ALK_ALT_CO2:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      DOC:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      DON:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      DOP:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      DOPr:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      DONr:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      DOCr:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      zooC:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      spChl:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      spC:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      spP:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      spFe:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      spCaCO3:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      diatChl:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      diatC:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      diatP:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      diatFe:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      diatSi:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      diazChl:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      diazC:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      diazP:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      diazFe:
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
      - 0.0
  _tracer_metadata:
    temp:
      units: degrees Celsius
      long_name: potential temperature
    salt:
      units: PSU
      long_name: salinity
    PO4:
      units: mmol/m^3
      long_name: dissolved inorganic phosphate
    NO3:
      units: mmol/m^3
      long_name: dissolved inorganic nitrate
    SiO3:
      units: mmol/m^3
      long_name: dissolved inorganic silicate
    NH4:
      units: mmol/m^3
      long_name: dissolved ammonia
    Fe:
      units: mmol/m^3
      long_name: dissolved inorganic iron
    Lig:
      units: mmol/m^3
      long_name: iron binding ligand
    O2:
      units: mmol/m^3
      long_name: dissolved oxygen
    DIC:
      units: mmol/m^3
      long_name: dissolved inorganic carbon
    DIC_ALT_CO2:
      units: mmol/m^3
      long_name: dissolved inorganic carbon, alternative CO2
    ALK:
      units: meq/m^3
      long_name: alkalinity
    ALK_ALT_CO2:
      units: meq/m^3
      long_name: alkalinity, alternative CO2
    DOC:
      units: mmol/m^3
      long_name: dissolved organic carbon
    DON:
      units: mmol/m^3
      long_name: dissolved organic nitrogen
    DOP:
      units: mmol/m^3
      long_name: dissolved organic phosphorus
    DOPr:
      units: mmol/m^3
      long_name: refractory dissolved organic phosphorus
    DONr:
      units: mmol/m^3
      long_name: refractory dissolved organic nitrogen
    DOCr:
      units: mmol/m^3
      long_name: refractory dissolved organic carbon
    zooC:
      units: mmol/m^3
      long_name: zooplankton carbon
    spChl:
      units: mg/m^3
      long_name: small phytoplankton chlorophyll
    spC:
      units: mmol/m^3
      long_name: small phytoplankton carbon
    spP:
      units: mmol/m^3
      long_name: small phytoplankton phosphorous
    spFe:
      units: mmol/m^3
      long_name: small phytoplankton iron
    spCaCO3:
      units: mmol/m^3
      long_name: small phytoplankton CaCO3
    diatChl:
      units: mg/m^3
      long_name: diatom chloropyll
    diatC:
      units: mmol/m^3
      long_name: diatom carbon
    diatP:
      units: mmol/m^3
      long_name: diatom phosphorus
    diatFe:
      units: mmol/m^3
      long_name: diatom iron
    diatSi:
      units: mmol/m^3
      long_name: diatom silicate
    diazChl:
      units: mg/m^3
      long_name: diazotroph chloropyll
    diazC:
      units: mmol/m^3
      long_name: diazotroph carbon
    diazP:
      units: mmol/m^3
      long_name: diazotroph phosphorus
    diazFe:
      units: mmol/m^3
      long_name: diazotroph iron

Creating CDR forcing from an existing YAML file#

Once we have the YAML file containing the CDR forcing parameters and release information, we can use it to recreate the exact same CDR forcing.

[64]:
the_same_cdr_forcing_with_volume_releases = CDRForcing.from_yaml(yaml_filepath)

The dataset contained in the .ds contains the same three releases as before.

[65]:
the_same_cdr_forcing_with_volume_releases.ds
[65]:
<xarray.Dataset> Size: 17kB
Dimensions:           (time: 9, ncdr: 3, ntracers: 34)
Coordinates:
  * time              (time) datetime64[ns] 72B 2010-01-01 ... 2012-12-31
    release_name      (ncdr) <U24 288B 'iceland_release' ... 'norway_release_...
    tracer_name       (ntracers) <U11 1kB 'temp' 'salt' ... 'diazP' 'diazFe'
    tracer_unit       (ntracers) <U15 2kB 'degrees Celsius' 'PSU' ... 'mmol/m^3'
    tracer_long_name  (ntracers) <U43 6kB 'potential temperature' ... 'diazot...
Dimensions without coordinates: ncdr, ntracers
Data variables:
    cdr_time          (time) float64 72B 3.653e+03 4.032e+03 ... 4.748e+03
    cdr_lon           (ncdr) float64 24B -10.0 -20.0 10.0
    cdr_lat           (ncdr) float64 24B 65.0 70.0 65.0
    cdr_dep           (ncdr) float64 24B 100.0 100.0 50.0
    cdr_hsc           (ncdr) float64 24B 0.0 0.0 0.0
    cdr_vsc           (ncdr) float64 24B 0.0 0.0 0.0
    cdr_interp        (ncdr) bool 3B False False False
    cdr_volume        (time, ncdr) float64 216B 1e+03 0.0 0.0 ... 1e+03 0.0 0.0
    cdr_tracer        (time, ntracers, ncdr) float64 7kB 20.0 20.0 ... 0.0
[ ]: