esbmtk package

Submodules

esbmtk.carbonate_chemistry module

esbmtk: A general purpose Earth Science box model toolkit Copyright (C), 2020-2021 Ulrich G. Wortmann

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

esbmtk.carbonate_chemistry.NDArrayFloat

First we define the actual function, carbonate_system_1_ode(). In the second step we create a wrapper init_carbonate_system_1() that defines how to integrate this function into esbmtk. In the third step we create a functiom that uses init_carbonate_system_1() to associates cs1 instances with the respective reservoirs.

The process for cs2 is analogous

Type:

Carbonate System 1 setup requires 3 steps

alias of ndarray[Any, dtype[float64]]

esbmtk.carbonate_chemistry.add_carbonate_system_1(rgs: list)[source]

Creates a new carbonate system virtual reservoir for each reservoir in rgs. Note that rgs must be a list of reservoir groups.

Required keywords:

rgs: list = [] of Reservoir Group objects

These new virtual reservoirs are registered to their respective Species as ‘cs’.

The respective data fields are available as rgs.r.cs.xxx where xxx stands for a given key key in the vr_datafields dictionary (i.e., H, CA, etc.)

esbmtk.carbonate_chemistry.add_carbonate_system_2(**kwargs) None[source]

Creates a new carbonate system virtual reservoir which will compute carbon species, saturation, compensation, and snowline depth, and compute the associated carbonate burial fluxes

Required keywords:

r_sb: list of Reservoir objects in the surface layer r_db: list of Reservoir objects in the deep layer carbonate_export_fluxes: list of flux objects which must match the list of Reservoir objects. zsat_min = depth of the upper boundary of the deep box z0 = upper depth limit for carbonate burial calculations typically zsat_min

Optional Parameters:

zsat = initial saturation depth (m) zcc = initial carbon compensation depth (m) zsnow = initial snowline depth (m) zsat0 = characteristic depth (m) Ksp0 = solubility product of calcite at air-water interface (mol^2/kg^2) kc = heterogeneous rate constant/mass transfer coefficient for calcite dissolution (kg m^-2 yr^-1) Ca2 = calcium ion concentration (mol/kg) pc = characteristic pressure (atm) pg = seawater density multiplied by gravity due to acceleration (atm/m) I = dissolvable CaCO3 inventory co3 = CO3 concentration (mol/kg) Ksp = solubility product of calcite at in situ sea water conditions (mol^2/kg^2)

esbmtk.carbonate_chemistry.carbonate_system_1(dic, ta, hplus_0, co2aq_0, p) tuple[source]
Calculates and returns the H+ and carbonate alkalinity concentrations

for the given reservoirgroup

Parameters:
  • dic – float with the dic concentration

  • ta – float with the ta concentration

  • hplus_0 – float with the H+ concentration

  • co2aq_0 – float with the [CO2]aq concentration

  • p – tuple with the parameter list

Returns:

dCdt_Hplus, dCdt_co2aq

LIMITATIONS: - Assumes all concentrations are in mol/kg - Assumes your Model is in mol/kg ! Otherwise, DIC and TA updating will not be correct.

Calculations are based off equations from: Boudreau et al., 2010, https://doi.org/10.1029/2009GB003654 Follows, 2006, doi:10.1016/j.ocemod.2005.05.004

esbmtk.carbonate_chemistry.carbonate_system_2(CaCO3_export: float, dic_t_db: float | tuple, ta_db: float, dic_t_sb: float | tuple, hplus_0: float, zsnow: float, p) tuple[source]

Calculates and returns the fraction of the carbonate rain that is dissolved an returned back into the ocean. This functions returns:

DIC_burial, DIC_burial_l, Hplus, zsnow

LIMITATIONS: - Assumes all concentrations are in mol/kg - Assumes your Model is in mol/kg

Calculations are based off equations from: Boudreau et al., 2010, https://doi.org/10.1029/2009GB003654

esbmtk.carbonate_chemistry.get_hplus(dic, ta, h0, boron, K1, K2, KW, KB) float[source]

Calculate H+ concentration based on a previous estimate [H+]. After Follows et al. 2006, doi:10.1016/j.ocemod.2005.05.004

Parameters:
  • dic – DIC in mol/kg

  • ta – TA in mol/kg

  • h0 – initial guess for H+ mol/kg

  • boron – boron concentration

  • K1 – Ksp1

  • K2 – Ksp2

  • KW – K_water

  • KB – K_boron

Returns H:

new H+ concentration in mol/kg

esbmtk.carbonate_chemistry.get_pco2(SW) float[source]

Calculate the concentration of pCO2

esbmtk.carbonate_chemistry.init_carbonate_system_1(rg: Reservoir)[source]

Creates a new carbonate system virtual reservoir for each reservoir in rgs. Note that rgs must be a list of reservoir groups.

Required keywords:

rgs: list = [] of Reservoir Group objects

These new virtual reservoirs are registered to their respective Species as ‘cs’.

The respective data fields are available as rgs.r.cs.xxx where xxx stands for a given key key in the vr_datafields dictionary (i.e., H, CA, etc.)

esbmtk.carbonate_chemistry.init_carbonate_system_2(export_flux: Flux, r_sb: Reservoir, r_db: Reservoir, kwargs: dict)[source]

Initialize a carbonate system 2 instance. Note that the current implmentation assumes that the export flux is the total export flux over surface area of the mixed layer, i.e., the sediment area between z0 and zmax

Parameters:
  • export_flux (Flux) – CaCO3 export flux from the surface box

  • r_sb (Reservoir) – Reservoir instance of the surface box

  • r_db (box) – Reservoir instance of the deep box

  • kwargs (dict) – dictionary of keyword value pairs

esbmtk.carbonate_chemistry.phc(m: float) float[source]

the reservoir class accepts a plot transform. here we use this to display the H+ concentrations as pH. After import, you can use it with like this in the reservoir definition

plot_transform_c=phc,

esbmtk.connections module

esbmtk.connections

Classes which handle the connections and fluxes between esbmtk objects like Species, Sources, and Sinks.

esbmtk: A general purpose Earth Science box model toolkit Copyright (C), 2020 Ulrich G. Wortmann

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

class esbmtk.connections.ConnectionProperties(**kwargs)[source]

Bases: esbmtkBase

Connect reservoir/sink/source groups when at least one of the arguments is a reservoirs_group object. This method will create regular connections for each matching species.

Use the connection.update() method to fine tune connections after creation

Example:

ConnectionProperties(source =  upstream reservoir / upstream reservoir group
   sink = downstrean reservoir / downstream reservoirs_group
   delta = defaults to zero and has to be set manually
   alpha =  defaults to zero and has to be set manually
   rate = shared between all connections
   ref_reservoirs = shared between all connections
   ref_flux = shared between all connections
   species = list, optional, if present, only these species will be connected
   ctype = needs to be set for all connections. Use "Regular"
           unless you require a specific connection type
   pl = [list]) process list. optional, shared between all connections
   id = optional identifier, passed on to individual connection
   plot = "yes/no" # defaults to yes, shared between all connections
)

ConnectionProperties(
          source=OM_Weathering,
          sink=Ocean,
          rate={DIC: f"{OM_w} Tmol/yr" ,
                ALK: f"{0} Tmol/yr"},
          ctype = {DIC: "Regular",
                   ALK: "Regular"},
        )
add_connections(**kwargs) None[source]

Add connections to the connection group

info() None[source]

List all connections in this group

exception esbmtk.connections.KeywordError(message)[source]

Bases: Exception

exception esbmtk.connections.ScaleFluxError(message)[source]

Bases: Exception

class esbmtk.connections.Species2Species(**kwargs)[source]

Bases: esbmtkBase

Two reservoirs connect to each other via at least one flux. This

module creates the connecting flux and creates a connector object which stores all connection properties.

For simple connections, the type flux type is derived implcitly from the specified parameters. For complex connections, the flux type must be set explicitly. See the examples below:

Parameters:
  • source: An object handle for a Source or Species

  • sink: An object handle for a Sink or Species

  • rate: A quantity (e.g., “1 mol/s”), optional

  • delta: The isotope ratio, optional

  • ref_reservoirs: Species or flux reference

  • alpha: A fractionation factor, optional

  • id: A string wich will become part of the object name, it will override automatic name creation

  • signal: An object handle of signal, optional

  • ctype: connection type, see below

  • bypass :str optional defaults to “None” see scale with flux

The connection name is derived automatically, see the documentation of __set_name__() for details

Connect Types:

Basic Connects (the advanced ones are below):

  • If both =rate= and =delta= are given, the flux is treated as a

    fixed flux with a given isotope ratio. This is usually the case for most source objects (they can still be affected by a signal, see above), but makes little sense for reservoirs and sinks.

  • If both the =rate= and =alpha= are given, the flux rate is fixed (subject to any signals), but the isotopic ratio of the output flux depends on the isotopic ratio of the upstream reservoir plus any isotopic fractionation specified by =alpha=. This is typically the case for fluxes which include an isotopic fractionation (i.e., pyrite burial). This combination is not particularly useful for source objects.

  • If the connection specifies only =delta= the flux is treated as a variable flux which is computed in such a way that the reservoir maintains steady state with respect to it’s mass.

  • If the connection specifies only =rate= the flux is treated as a fixed flux which is computed in such a way that the reservoir maintains steady state with respect to it’s isotope ratio.

Connecting a Source to a Species

Unless you use a Signal, a source typically provides a steady stream with a given isotope ratio (if used)

Example:

Species2Species(source =  Source,
        sink = downstrean reservoir,
        rate = "1 mol/s",
        delta = optional,
        signal = optional, see the signal documentation
        )

Connecting a Species to Sink or another Species

Here we can distinguish between cases where we use fixed flux, or a flux that reacts to in some way to the

upstream reservoir (see the Species to Species section for a more complete treatment):

Fixed outflux, with no isotope fractionation

Example:

Species2Species(source =  upstream reservoir,
      sink = Sink,
      rate = "1 mol/s",
      )

Fixed outflux, with isotope fractionation

Example:

Species2Species(source =  upstream reservoir,
      sink = Sink,
      alpha = -28,
      rate = "1 mol/s",
      )

Advanced Connects

You can aditionally define connection properties via the ctype keyword. This requires additional keyword parameters. The following values are recognized

ctype = “scale_with_flux”

This will scale a flux relative to another flux:

Example:

Species2Species(source =  upstream reservoir,
        sink = downstream reservoir,
        ctype = "scale_with_flux",
        ref_flux = flux handle,
        scale = 1, #
        )

ctype = “scale_with_concentration”

This will scale a flux relative to the mass or concentration of a reservoir

Example:

Species2Species(source =  upstream reservoir,
       sink = downstream reservoir,
       ctype = "scale_with_concentration",
       ref_reservoirs = reservoir handle,
       scale = 1, # scaling factor
       )

Useful methods in this class

The following methods might prove useful:

  • info() will provide a short description of the connection objects.

  • list_processes() which will list all the processes which are associated with this connection.

  • update() which allows you to update connection properties after the connection has been created

property alpha: float | int
property delta: float | int
get_species(r1, r2) None[source]

In most cases the species is set by r2. However, if we have backward fluxes the species depends on the r2

info(**kwargs) None[source]

Show an overview of the object properties. Optional arguments are index :int = 0 this will show data at the given index indent :int = 0 indentation

property rate: float | int
update(**kwargs)[source]

Update connection properties. This will delete existing processes and fluxes, replace existing key-value pairs in the self.kwargs dict, and then re-initialize the connection.

exception esbmtk.connections.Species2SpeciesError(message)[source]

Bases: Exception

esbmtk.esbmtk module

esbmtk: A general purpose Earth Science box model toolkit Copyright (C), 2020 Ulrich G. Wortmann

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

class esbmtk.esbmtk.ElementProperties(**kwargs)[source]

Bases: esbmtkBase

Each model, can have one or more elements. This class sets element specific properties

Example:

ElementProperties(name      = "S "           # the element name
        model     = Test_model     # the model handle
        mass_unit =  "mol",        # base mass unit
        li_label  =  "$^{32$S",    # Label of light isotope
        hi_label  =  "$^{34}S",    # Label of heavy isotope
        d_label   =  r"$\delta^{34}$S",  # Label for delta value
        d_scale   =  "VCDT",       # Isotope scale
        r         = 0.044162589,   # isotopic abundance ratio for element
        reference = "https://// or citation",
      )
list_species() None[source]

List all species which are predefined for this element

class esbmtk.esbmtk.Flux(**kwargs: dict[str, any])[source]

Bases: esbmtkBase

A class which defines a flux object. Flux objects contain information which links them to an species, describe things like the mass and time unit, and store data of the total flux rate at any given time step. Similarly, they store the flux of the light and heavy isotope flux, as well as the delta of the flux. This is typically handled through the Species2Species object. If you set it up manually

Example:

Flux = (name = "Name" # optional, defaults to _F
     species = species_handle,
     delta = any number,
     rate  = "12 mol/s" # must be a string
     display_precision = number, optional, inherited from Model

)

You can access the flux data as

  • Name.m # mass

  • Name.d # delta

  • Name.c # same as Name.m since flux has no concentration

info(**kwargs) None[source]

Show an overview of the object properties. Optional arguments are:

Parameters:
  • index – int = 0 this will show data at the given index

  • indent – int = 0 indentation

exception esbmtk.esbmtk.FluxError(message)[source]

Bases: Exception

class esbmtk.esbmtk.Model(**kwargs: dict[any, any])[source]

Bases: esbmtkBase

This class is used to specify a new model. See the __init__() method for a detailed explanation of the parameters

The user facing methods of the model class are

  • Model_Name.info()

  • Model_Name.save_data()

  • Model_Name.plot([sb.DIC, sb.TA]) plot any object in the list

  • Model_Name.save_state() Save the model state

  • Model_name.read_state() Initialize with a previous model state

  • Model_Name.run()

  • Model_Name.list_species()

  • Model_name.flux_summary()

  • Model_Name.connection_summary()

clear()[source]

delete all model objects

connection_summary(**kwargs: dict) None[source]

Show a summary of all connections

Optional parameters:

Parameters:
  • filter_by – str = “” # filter on connection id. If more than one word is provided, all words must match

  • return_list – bool if set, return a list object instead of printing to the terminal

flux_summary(**kwargs: dict)[source]

Show a summary of all model fluxes

Optional parameters:

Parameters:
  • filter_by – str = “” # filter on flux name or part of flux name words separated by blanks act as additional conditions, i.e., all words must occur in a given name

  • return_list – bool = False, # if True return a list of fluxes matching the filter_by string.

  • exclude

    str = “” # exclude all results matching this string

    Example:

    names = M.flux_summary(filter_by="POP A_sb", return_list=True)
    

get_delta_values()[source]

Calculate masses and isotope ratios in the usual delta notation

info(**kwargs) None[source]

Show an overview of the object properties. Optional arguments are (name/default/explanation)

Parameters:
  • index – int = 0 # this will show data at the given index

  • indent – int = 0 # print indentation

list_species()[source]

List all defined species.

merge_temp_results()[source]

Replace the datafields which were used for an individual iteration with the data we saved from the previous iterations

ode_solver(kwargs)[source]

Use the ode solver

plot(pl: list = None, **kwargs) None[source]

Plot all objects specified in pl

Parameters:

pl – a list of ESBMTK instance (e.g., reservoirs)

optional keywords: fn = filename, defaults to the Model name

Example:

M.plot([sb.PO4, sb.DIC], fn='test.pdf')

will plot sb.PO4 and sb.DIC and save the plot as ‘test.pdf’

post_process_data(results) None[source]

Map solver results back into esbmtk structures

Parameters:

results – numpy arrays with solver results

read_data(directory='./data') None[source]

Save the model results to a CSV file. Each reservoir will have their own CSV file

read_state(directory='state')[source]

This will initialize the model with the result of a previous model run. For this to work, you will need issue a Model.save_state() command at then end of a model run. This will create the necessary data files to initialize a subsequent model run.

restart()[source]

Restart the model with result of the last run. This is useful for long runs which otherwise would used to much memory

run(**kwargs) None[source]

Loop over the time vector, and for each time step, calculate the fluxes for each reservoir

save_data(directory='./data') None[source]

Save the model results to a CSV file. Each reservoir will have their own CSV file

Calling save_data() without any arguments, will create (or recreate) the data directory in the current working directory which will then be populated by csv-files

Parameters:

directory – a string with the directory name. It defaults to ‘data’

save_state(directory='state') None[source]

Save model state. Similar to save data, but only saves the last 10 time-steps

sub_sample_data()[source]

Subsample the data. No need to save 100k lines of data You need to do this _after_ saving the state, but before plotting and saving the data

test_d_pH(rg: Species, time: ndarray[Any, dtype[float64]]) None[source]

Test if the change in pH exceeds more than 0.01 units per time step. Note that this is only a crude test, since the solver interpolates between intergration steps. So this may not catch all problems.

Parameters:
  • rg (Reservoir) – Reservoir instance

  • time (: NDArrayFloat) – time vector as returned by the solver

exception esbmtk.esbmtk.ModelError(message)[source]

Bases: Exception

exception esbmtk.esbmtk.ReservoirError(message)[source]

Bases: Exception

exception esbmtk.esbmtk.ScaleError(message)[source]

Bases: Exception

class esbmtk.esbmtk.Sink(**kwargs)[source]

Bases: SourceSink

This is a meta class to setup a Source/Sink objects. These are not actual reservoirs, but we stil need to have them as objects Example:

Sink(name = "Pyrite",
    species = SO4,
    display_precision = number, optional, inherited from Model
    delta = number or str. optional defaults to "None"
    register = Model handle
)
class esbmtk.esbmtk.Source(**kwargs)[source]

Bases: SourceSink

This is a meta class to setup a Source/Sink objects. These are not actual reservoirs, but we stil need to have them as objects Example:

Ssource(name = "weathering",
    species = SO4,
    display_precision = number, optional, inherited from Model
    delta = number or str. optional defaults to "None"
    register = Model handle
)
class esbmtk.esbmtk.SourceSink(**kwargs)[source]

Bases: esbmtkBase

This is a meta class to setup a Source/Sink objects. These are not actual reservoirs, but we stil need to have them as objects Example:

Sink(name = "Pyrite",
    species = SO4,
    display_precision = number, optional, inherited from Model
    delta = number or str. optional defaults to "None"
    register = Model handle
)
property delta
class esbmtk.esbmtk.Species(**kwargs)[source]

Bases: SpeciesBase

This object holds reservoir specific information.

Example:

Species(name = "foo",      # Name of reservoir
          species = S,          # SpeciesProperties handle
          delta = 20,           # initial delta - optional (defaults  to 0)
          mass/concentration = "1 unit"  # species concentration or mass
          volume/geometry = "1E5 l",      # reservoir volume (m^3)
          plot = "yes"/"no", defaults to yes
          plot_transform_c = a function reference, optional (see below)
          legend_left = str, optional, useful for plot transform
          display_precision = number, optional, inherited from Model
          register = Model instance
          isotopes = True/False otherwise use Model.m_type
          seawater_parameters= dict, optional
          )

You must either give mass or concentration. The result will always be displayed as concentration though.

You must provide either the volume or the geometry keyword. In the latter case provide a list where the first entry is the upper depth datum, the second entry is the lower depth datum, and the third entry is the total ocean area. E.g., to specify the upper 200 meters of the entire ocean, you would write:

geometry=[0,-200,3.6e14]

the corresponding ocean volume will then be calculated by the calc_volume method in this case the following instance variables will also be set:

self.volume in model units (usually liter) self.are:a surface area in m^2 at the upper bounding surface self.sed_area: area of seafloor which is intercepted by this box. self.area_fraction: area of seafloor which is intercepted by this relative to the total ocean floor area

It is also possible to specify volume and area explicitly. In this case provide a dictionary like this:

geometry = {"area": "1e14 m**2", # surface area
            "volume": "3e16 m**3", # box volume
           }

Adding seawater_properties:

If this optional parameter is specified, a SeaWaterConstants instance will be registered for this Species as Species.swc See the SeaWaterConstants class for details how to specify the parameters, e.g.:

seawater_parameters = {"temperature": 2,
                       "pressure": 240,
                       "salinity" : 35,
                      }

Using a transform function:

In some cases, it is useful to transform the reservoir concentration data before plotting it. A good example is the H+ concentration in water which is better displayed as pH. We can do this by specifying a function to convert the reservoir concentration into pH units:

.. code-block:: python
def phc(c :float) -> float:

# Calculate concentration as pH. c can be a number or numpy array import numpy as np pH :float = -np.log10(c) return pH

this function can then be added to a reservoir as:

hplus.plot_transform_c = phc

You can modify the left legend to suit the transform via the legend_left keyword

Note, at present the plot_transform_c function will only take one argument, which always defaults to the reservoir concentration. The function must return a single argument which will be interpreted as the transformed reservoir concentration.

Accesing Species Data:

You can access the reservoir data as:

  • Name.m # mass

  • Name.d # delta

  • Name.c # concentration

Useful methods include:

  • Name.write_data() # save data to file

  • Name.info() # info Species

property concentration: float
property delta: float
property mass: float
class esbmtk.esbmtk.SpeciesBase(**kwargs)[source]

Bases: esbmtkBase

Base class for all Species objects

get_plot_format()[source]

Return concentrat data in plot units

info(**kwargs) None[source]

Show an overview of the object properties. Optional arguments are

Parameters:
  • index – int = 0 # this will show data at the given index

  • indent – int = 0 # print indentation

class esbmtk.esbmtk.SpeciesProperties(**kwargs)[source]

Bases: esbmtkBase

Each model, can have one or more species. This class sets species specific properties

Example:

SpeciesProperties(name = "SO4",
        element = S,

)

Defaults:

self.defaults: dict[any, any] = {
    "name": ["None", (str)],
    "element": ["None", (ElementProperties, str)],
    "display_as": [kwargs["name"], (str)],
    "m_weight": [0, (int, float, str)],
    "register": ["None", (Model, ElementProperties, Species, GasReservoir)],
    "parent": ["None", (Model, ElementProperties, Species, GasReservoir)],
    "flux_only": [False, (bool)],
    "logdata": [False, (bool)],
    "scale_to": ["None", (str)],
    "stype": ["concentration", (str)],
}

Required keywords: “name”, “element”

esbmtk.esbmtk_base module

esbmtk: A general purpose Earth Science box model toolkit Copyright (C), 2020 Ulrich G. Wortmann

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

This module defines some shared methods

exception esbmtk.esbmtk_base.FluxSpecificationError(message)[source]

Bases: Exception

exception esbmtk.esbmtk_base.InputError(message)[source]

Bases: Exception

exception esbmtk.esbmtk_base.KeywordError(message)[source]

Bases: Exception

exception esbmtk.esbmtk_base.MissingKeywordError(message)[source]

Bases: Exception

exception esbmtk.esbmtk_base.SpeciesPropertiesMolweightError(message)[source]

Bases: Exception

class esbmtk.esbmtk_base.esbmtkBase[source]

Bases: input_parsing

The esbmtk base class template. This class handles keyword arguments, name registration and other common tasks

Useful methods in this class:

define required keywords in lrk dict:

self.lrk: list = [“name”]

define allowed type per keyword in lkk dict:
self.defaults: dict[str, list[any, tuple]] = {

“name”: [“None”, (str)], “model”: [“None”,(str, Model)], “salinity”: [35, (int, float)], # int or float }

parse and register all keywords with the instance self.__initialize_keyword_variables__(kwargs)

register the instance self.__register_name_new__ ()

ensure_q(arg)[source]

Test that a given input argument is a quantity. If not convert into quantity

help() None[source]

Show all keywords, their fdefault values and allowed types.

info(**kwargs) None[source]

Show an overview of the object properties. Optional arguments are

indent :int = 0 indentation

set_flux(mass: str, time: str, substance: SpeciesProperties)[source]

set_flux converts() a flux rate that is specified as rate, time, substance so that it matches the correct model units (i.e., kg/s or mol/s)

Example:

M.set_flux("12 Tmol", "year", M.C)

if model mass units are in mol, no change will be made if model mass units are in kg, the above will return kg C/a (and vice verso)

Parameters:
  • mass – e.g., “12 Tmol”

  • time – e.g., “year”

  • substance – e.g., SpeciesProperties Instance e.g., M.PO4

Returns:

mol/year or g/year

Raises:

FluxSpecificationError

Raises:

SpeciesPropertiesMolweightError

class esbmtk.esbmtk_base.input_parsing[source]

Bases: object

Provides various routines to parse and process keyword arguments. All derived classes need to declare the allowed keyword arguments, their defualt values and the type in the following format:

defaults = {“key”: [value, (allowed instances)]

the recommended sequence is to first set default values via __register_variable_names__()

__update_dict_entries__(defaults,kwargs) will compare the provided kwargs against this data, and upon succesful parsing update the default dict with the new values

esbmtk.extended_classes module

class esbmtk.extended_classes.DataField(**kwargs: dict[str, any])[source]

Bases: esbmtkBase

DataField: Datafields can be used to plot data which is computed after the model finishes in the overview plot windows. Therefore, datafields will plot in the same window as the reservoir they are associated with. Datafields must share the same x-axis is the model, and can have up to two y axis.

Example:

DataField(name = "Name"
          register = Model handle,
          y1_data = NDArrayFloat or list of arrays
          y1_label = Data label(s)
          y1_legend = Y-Axis Label
          y1_type = "plot", | "scatter"
          y2_data = NDArrayFloat    # optional
          y2_legend = Y-Axis label # optional
          y2_label = Data legend(s) # optional
          y2_type = "plot", | "scatter"
          common_y_scale = "no",  #optional, default "no"
          display_precision = number, optional, inherited from Model
          )

Note that Datafield data is not mapped to model units. Care must be taken that the data units match the model units.

The instance provides the following data

Name.x = X-axis = model X-axis Name.y1_data Name.y1_label Name.y1_legend

Similarly for y2

You can specify more than one data set, and be explicit about color and linestyle choices.

Example:

DataField(
        name="df_pH",
        x1_data=[M.time, M.time, M.time, M.ef_hplus_l.x, M.ef_hplus_h.x, M.ef_hplus_d.x],
        y1_data=[
        -np.log10(M.L_b.Hplus.c),
        -np.log10(M.H_b.Hplus.c),
        -np.log10(M.D_b.Hplus.c),
        -np.log10(M.ef_hplus_l.y),
        -np.log10(M.ef_hplus_h.y),
        -np.log10(M.ef_hplus_d.y),
        ],
        y1_label="Low latitude, High latitude, Deep box, d_L, d_H, d_D".split(", "),
        y1_color="C0 C1 C2 C0 C1 C2".split(" "),
        y1_style="solid solid solid dotted dotted dotted".split(" "),
        y1_legend="pH",
        register=M,
        )
exception esbmtk.extended_classes.DataFieldError(message)[source]

Bases: Exception

exception esbmtk.extended_classes.ESBMTKFunctionError(message)[source]

Bases: Exception

class esbmtk.extended_classes.ExternalCode(**kwargs)[source]

Bases: SpeciesNoSet

This class can be used to implement user provided functions. The data inside a VR_no_set instance will only change in response to a user provided function but will otherwise remain unaffected. That is, it is up to the user provided function to manage changes in reponse to external fluxes. A VR_no_set is declared in the following way:

ExternalCode(
            name="cs",     # instance name
            species=CO2,   # species, must be given
            # the vr_data_fields contains any data that is referenced inside the
            # function, rather than passed as argument, and all data that is
            # explicitly referenced by the model
            vr_datafields :dict ={"Hplus": self.swc.hplus,
                                  "Beta": 0.0},
            function=calc_carbonates, # function reference, see below
            fname = function name as string
            function_input_data="DIC TA",
            # Note that parameters must be individual float values
            function_params:tuple(float)
            # list of return values
            return_values={  # these must be known speces definitions
                          "Hplus": rg.swc.hplus,
                           "zsnow": float(abs(kwargs["zsnow"])),
                           },
            register=rh # reservoir_handle to register with.
        )

the dict keys of vr_datafields will be used to create alias
names which can be used to access the respective variable

The general template for a user defined function is a follows:

def calc_carbonates(i: int, input_data: list, vr_data: list, params: list) -> None:
    # i = index of current timestep
    # input_data = list of np.arrays, typically data from other Species
    # vr_data = list of np.arrays created during instance creation (i.e. the vr data)
    # params = list of float values (at least one!)
    pass
 return

Note that this function should not return any values, and that all input fields must have at least one entry!

append(**kwargs) None[source]

This method allows to update GenericFunction parameters after the VirtualSpecies has been initialized. This is most useful when parameters have to reference other virtual reservoirs which do not yet exist, e.g., when two virtual reservoirs have a circular reference.

Example:

VR.update(a1=new_parameter, a2=new_parameter)
create_alialises() None[source]

Register alialises for each vr_datafield

update_parameter_count()[source]
class esbmtk.extended_classes.ExternalData(**kwargs: dict[str, str])[source]

Bases: esbmtkBase

Instances of this class hold external X/Y data which can be associated with a reservoir.

Example:

ExternalData(name       = "Name"
             filename   = "filename",
             legend     = "label",
             offset     = "0 yrs",
             reservoir  = reservoir_handle,
             scale      = scaling factor, optional
             display_precision = number, optional, inherited from Model
             convert_to = optional, see below
            )

The data must exist as CSV file, where the first column contains the X-values, and the second column contains the Y-values.

The x-values must be time and specify the time units in the header between square brackets They will be mapped into the model time units.

The y-values can be any data, but the user must take care that they match the model units defined in the model instance. So your data file mujst look like this

Time [years], Data [units], Data [units] 1, 12 2, 13

By convention, the secon column should contaain the same type of data as the reservoir (i.e., a concentration), whereas the third column contain isotope delta values. Columns with no data should be left empty (and have no header!) The optional scale argument, will only affect the Y-col data, not the isotope data

The column headers are only used for the time or concentration data conversion, and are ignored by the default plotting methods, but they are available as self.xh,yh

The file must exist in the local working directory.

the convert_to keyword can be used to force a specific conversion. The default is to convert into the model concentration units.

- name.plot()
Data:
  • name.x

  • name.y

  • name.df = dataframe as read from csv file

plot() None[source]

Plot the data and save a pdf

Example:

ExternalData.plot()
exception esbmtk.extended_classes.ExternalDataError(message)[source]

Bases: Exception

exception esbmtk.extended_classes.FluxError(message)[source]

Bases: Exception

class esbmtk.extended_classes.GasReservoir(**kwargs)[source]

Bases: SpeciesBase

This object holds reservoir specific information similar to the Species class

Example:

Species(name = "foo",     # Name of reservoir
          species = CO2,    # SpeciesProperties handle
          delta = 20,       # initial delta - optional (defaults  to 0)
          reservoir_mass = quantity # total mass of all gases
                           defaults to 1.833E20 mol
          species_ppm =  number # concentration in ppm
          plot = "yes"/"no", defaults to yes
          plot_transform_c = a function reference, optional (see below)
          legend_left = str, optional, useful for plot transform
          display_precision = number, optional, inherited from Model
          register = optional, use to register with Reservoir Group
          isotopes = True/False otherwise use Model.m_type
          )

Accesing Species Data:

You can access the reservoir data as:

  • Name.m # species mass

  • Name.l # mass of light isotope

  • Name.d # species delta (only avaible after M.get_delta_values()

  • Name.c # partial pressure

  • Name.v # total gas mass

Useful methods include:

  • Name.write_data() # save data to file

  • Name.info() # info Species

exception esbmtk.extended_classes.GasResrvoirError(message)[source]

Bases: Exception

class esbmtk.extended_classes.Reservoir(**kwargs)[source]

Bases: esbmtkBase

This class allows the creation of a group of reservoirs which share a common volume, and potentially connections. E.g., if we have twoy reservoir groups with the same reservoirs, and we connect them with a flux, this flux will apply to all reservoirs in this group.

A typical examples might be ocean water which comprises several species. A reservoir group like ShallowOcean will then contain sub-reservoirs like DIC in the form of ShallowOcean.DIC

Example:

Reservoir(name = "ShallowOcean",        # Name of reservoir group
            volume/geometry = "1E5 l",       # see below
            delta   = {DIC:0, TA:0, PO4:0]  # dict of delta values
            mass/concentration = {DIC:"1 unit", TA: "1 unit"}
            plot = {DIC:"yes", TA:"yes"}  defaults to yes
            isotopes = {DIC: True/False} see Species class for details
            seawater_parameters = dict, optional, see below
            register= model handle, required
       )
Notes: The subreservoirs are derived from the keys in the concentration or mass

dictionary. Toward this end, the keys must be valid species handles and – not species names – !

Connecting two reservoir groups requires that the names in both group match, or that you specify a dictionary which delineates the matching.

Most parameters are passed on to the Species class. See the reservoir class documentation for details

The geometry keyword specifies the upper depth interval, the lower depth interval, and the fraction of the total ocean area inhabited by the reservoir

If the geometry parameter is supplied, the following instance variables will be computed:

  • self.volume: in model units (usually liter)

  • self.area: surface area in m^2 at the upper bounding surface

  • self.sed_area: area of seafloor which is intercepted by this box.

  • self.area_fraction: area of seafloor which is intercepted by this relative to the total ocean floor area

seawater_parameters:

If this optional parameter is specified, a SeaWaterConstants instance will be registered for this Species as Species.swc See the SeaWaterConstants class for details how to specify the parameters, e.g.:

seawater_parameters = {"temperature": 2,
                   "pressure": 240,
                   "salinity" : 35,
                   },
exception esbmtk.extended_classes.ReservoirError(message)[source]

Bases: Exception

class esbmtk.extended_classes.Signal(**kwargs)[source]

Bases: esbmtkBase

This class will create a signal which is described by its startime (relative to the model time), it’s size (as mass) and duration, or as duration and magnitude. Furthermore, we can presribe the signal shape (square, pyramid, bell, file )and whether the signal will repeat. You can also specify whether the event will affect the delta value.

The default is to add the signal to a given connection. It is however also possible to use the signal data as a scaling factor.

Example:

Signal(name = "Name",
       species = SpeciesProperties handle,
       start = "0 yrs",     # optional
       duration = "0 yrs",  #
       delta = 0,           # optional
       stype = "addition"   # optional, currently the only type
       shape = "square/pyramid/bell/filename"
       mass/magnitude/filename  # give one
       offset = '0 yrs',     #
       scale = 1, optional,  #
       offset = option #
       reservoir = r-handle # optional, see below
       source = s-handle optional, see below
       display_precision = number, optional, inherited from Model
       register,
      )

Signals are cumulative, i.e., complex signals ar created by adding one signal to another (i.e., Snew = S1 + S2)

The optional scaling argument will only affect the y-column data of external data files

Signals are registered with a flux during flux creation, i.e., they are passed on the process list when calling the connector object.

if the filename argument is used, you can provide a filename which contains the data to be used in csv format. The data will be interpolated to the model domain, and added to the already existing data. The external data need to be in the following format

Time, Rate, delta value 0, 10, 12

i.e., the first row needs to be a header line

All time data in the csv file will be treated as realative time (i.e., the start time will be mapped to zero). Use the offset keyword to shift the external signal data in the time domain.

Last but not least, you can provide an optional reservoir name. In this case, the signal will create a source as (signal_name_source) and the connection to the specified reservoir. If you build a complex signal do this as the last step. If you additionally provide a source name the connection will be made between the provided source (this can be useful if you use source groups).

This class has the following methods

Signal.repeat() Signal.plot() Signal.info()

repeat(start, stop, offset, times) None[source]

This method creates a new signal by repeating an existing signal. Example:

new_signal = signal.repeat(start,   # start time of signal slice to be repeated
                           stop,    # end time of signal slice to be repeated
                           offset,  # offset between repetitions
                           times,   # number of time to repeat the slice
                           )
exception esbmtk.extended_classes.SignalError(message)[source]

Bases: Exception

class esbmtk.extended_classes.SinkProperties(**kwargs)[source]

Bases: SourceSinkProperties

This is just a wrapper to setup a Sink object Example:

SinkProperties(name = "Burial",
     species = [SO42, H2S],
     delta = {"SO4": 10}
     )
class esbmtk.extended_classes.SourceProperties(**kwargs)[source]

Bases: SourceSinkProperties

This is just a wrapper to setup a Source object Example:

SourceProperties(name = "weathering",
        species = [SO42, H2S],
        delta = {"SO4": 10}
        )
class esbmtk.extended_classes.SourceSinkProperties(**kwargs)[source]

Bases: esbmtkBase

This is a meta class to setup Source/Sink Groups. These are not actual reservoirs, but we stil need to have them as objects Example:

SinkProperties(name = "Pyrite",
     species = [SO42, H2S],
     )

where the first argument is a string, and the second is a reservoir handle

exception esbmtk.extended_classes.SourceSinkPropertiesError(message)[source]

Bases: Exception

class esbmtk.extended_classes.SpeciesNoSet(**kwargs)[source]

Bases: SpeciesBase

This class is similar to a regular reservoir, but we make no assumptions about the type of data contained. I.e., all data will be left alone

class esbmtk.extended_classes.VectorData(**kwargs: dict[str, any])[source]

Bases: esbmtkBase

get_plot_format()[source]

Return concentrat data in plot units

class esbmtk.extended_classes.VirtualSpecies(**kwargs)[source]

Bases: Species

A virtual reservoir. Unlike regular reservoirs, the mass of a virtual reservoir depends entirely on the return value of a function.

Example:

VirtualSpecies(name="foo",
            volume="10 liter",
            concentration="1 mmol",
            species=  ,
            function=bar,
            a1 to a3 =  to 3optional function arguments,
            display_precision = number, optional, inherited from Model,
            )

the concentration argument will be used to initialize the reservoir and to determine the display units.

The function definition follows the GenericFunction class. which takes a generic function and up to 6 optional function arguments, and will replace the mass value(s) of the given reservoirs with whatever the function calculates. This is particularly useful e.g., to calculate the pH of a given reservoir as function of e.g., Alkalinity and DIC. :param - name = name of process: :param : :param - act_on = name of a reservoir this process will act upon: :param - function = a function reference: :param - a1 to a3 function arguments:

The function must return a list of numbers which correspond to the data which describe a reservoir i.e., mass, light isotope, heavy isotope, delta, and concentration

In order to use this function we need first declare a function we plan to use with the generic function process. This function needs to follow this template:

def my_func(i, a1, a2, a3) -> tuple:
    #
    # i = index of the current timestep
    # a1 to a3 =  optional function parameter. These must be present,
    # even if your function will not use it See above for details

    # calc some stuff and return it as

    return [m, l, h, d, c] # where m= mass, and l & h are the respective
                           # isotopes. d denotes the delta value and
                           # c the concentration
                           # Use dummy value as necessary.

This class provides an update method to resolve cases where e.g., two virtual reservoirs have a circular reference. See the documentation of update().

update(**kwargs) None[source]

This method allows to update GenericFunction parameters after the VirtualSpecies has been initialized. This is most useful when parameters have to reference other virtual reservoirs which do not yet exist, e.g., when two virtual reservoirs have a circular reference.

Example:

VR.update(a1=new_parameter, a2=new_parameter)
class esbmtk.extended_classes.VirtualSpeciesNoSet(**kwargs)[source]

Bases: ExternalCode

Alias to ensure backwards compatibility

esbmtk.ode_backend module

esbmtk: A general purpose Earth Science box model toolkit Copyright (C), 2020 Ulrich G. Wortmann

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

esbmtk.ode_backend.check_isotope_effects(f_m: str, c: Species2Species, icl: dict, ind3: str, ind2: str) str[source]

Test if the connection involves any isotope effects

Parameters:
  • f_m – string with the flux name

  • c – connection object

  • icl – dict of reservoirs that have actual fluxes

  • ind2 – indent 2 times

  • ind3 – indent 3 times

Returns eq:

equation string

esbmtk.ode_backend.check_signal_2(ex: str, exl: str, c: Species2Species)[source]

Test if connection is affected by a signal

Parameters:
  • ex – equation string

  • c – connection object

Returns:

(modified) equation string

esbmtk.ode_backend.get_flux(flux: Flux, M: Model, R: list[float], icl: dict)[source]

Create formula expressions that calcultes the flux F. Return the equation expression as string

Parameters:
  • flux – The flux object for which we create the equation

  • M – The current model object

  • R – The list of initial conditions for each reservoir

  • icl – dict of reservoirs that have actual fluxes

Returns:

A tuple where the first string is the equation for the total flux, and the second string is the equation for the flux of the light isotope

esbmtk.ode_backend.get_ic(r: Species, icl: dict, isotopes=False) str[source]

Get initial condition in a reservoir. If the reservoir is icl, return index expression into R.c. If the reservoir is not in the index, return the Species concentration a t=0

In both cases return these a string

If isotopes == True, return the pointer to the light isotope concentration

Parameters:
  • r – A reservoir handle

  • icl – icl = dict[Species, list[int, int]] where reservoir indicates the reservoir handle, and the list contains the index into the reservoir data. list[0] = concentration list[1] concentration of the light isotope.

Raises:

ValueError – get_ic: can’t find {r.full_name} in list of initial conditions

Returns:

the string s which is the full_name of the reservoir concentration or isotope concentration

esbmtk.ode_backend.get_initial_conditions(M: Model, rtol: float, atol_d: float = 1e-07) tuple[list, dict, list, list, NDArrayFloat][source]

Get list of initial conditions. This list needs to match the number of equations.

Parameters:
  • Model – The model handle

  • rtol – relative tolerance for BDF solver.

  • atol_d – default value for atol if c = 0

Returns:

R = list of initial conditions as floats

Returns:

icl = dict[Species, list[int, int]] where reservoir indicates the reservoir handle, and the list contains the index into the reservoir data. list[0] = concentration list[1] concentration of the light isotope.

Returns:

cpl = list of reservoirs that use function to evaluate reservoir data

Returns:

ipl = list of static reservoirs that serve as input

Returns:

rtol = array of tolerence values for ode solver

We need to consider 3 types of reservoirs:

1) Species that change as a result of physical fluxes i.e. r.lof > 0. These require a flux statements and a reservoir equation.

2) Species that do not have active fluxes but are computed as a tracer, i.e.. HCO3. These only require a reservoir equation

3) Species that do not change but are used as input. Those should not happen in a well formed model, but we cannot exclude the possibility. In this case, there is no flux equation, and we state that dR/dt = 0

get_ic() will look up the index position of the reservoir_handle on icl, and then use this index to retrieve the correspinding value in R

Isotopes are handled by adding a second entry

esbmtk.ode_backend.get_regular_flux_eq(flux: Flux, c: Species2Species, icl: dict, ind2, ind3) tuple[source]

Create a string containing the equation for a regular (aka fixed rate) connection

Parameters:
  • flux – flux instance

  • c – connection object

  • icl – dict of reservoirs that have actual fluxes

  • ind2 – indent 2 times

  • ind3 – indent 3 times

Returns:

two strings, where the first describes the equation for the total flux, and the second describes the rate for the light isotope

esbmtk.ode_backend.get_scale_with_concentration_eq(flux: Flux, c: Species2Species, cfn: str, icl: dict, ind2: str, ind3: str)[source]

Create equation string defining a flux that scales with the concentration in the upstream reservoir

Example: M1_CG_D_b_to_L_b_TA_thc__F = M1.CG_D_b_to_L_b.TA_thc.scale * R[5]

Parameters:
  • flux – Flux object

  • c – connection instance

  • cfn – full name of the connection instance

  • icl – dict[Species, list[int, int]] where reservoir indicates the reservoir handle, and the list contains the index into the reservoir data. list[0] = concentration list[1] concentration of the light isotope.

Returns:

two strings with the respective equations for the change in the total reservoir concentration and the concentration of the light isotope

esbmtk.ode_backend.get_scale_with_flux_eq(flux: Flux, c: Species2Species, cfn: str, icl: dict, ind2: str, ind3: str)[source]

Equation defining a flux that scales with strength of another flux. If isotopes are used, use the isotope ratio of the upstream reservoir.

Parameters:
  • flux – Flux object

  • c – connection instance

  • cfn – full name of the connection instance

  • icl – dict[Species, list[int, int]] where reservoir indicates the reservoir handle, and the list contains the index into the reservoir data. list[0] = concentration list[1] concentration of the light isotope.

Returns:

two strings with the respective equations for the change in the total reservoir concentration and the concentration of the light isotope

esbmtk.ode_backend.parse_esbmtk_input_data_types(d: any, r: Species, ind: str, icl: dict) str[source]

Parse esbmtk data types that are provided as arguments to external function objects, and convert them into a suitable string format that can be used in the ode equation file

esbmtk.ode_backend.parse_function_params(params, ind) str[source]

Parse function_parameters and convert them into a suitable string format that can be used in the ode equation file

esbmtk.ode_backend.write_ef(eqs, ef: Species | ExternalFunction, icl: dict, rel: str, ind2: str, ind3: str, gpt: tuple) str[source]

Write external function call code

Parameters:
  • eqs – equation file handle

  • ef – external_function handle

  • icl – dict of reservoirs that have actual fluxes

  • rel – string with reservoir names returned by setup_ode

  • ind2 – indent 2 times

  • ind3 – indent 3 times

  • gpt – tuple with global paramaters

Returns:

rel: modied string of reservoir names

esbmtk.ode_backend.write_equations_2(M: Model, R: list[float], icl: dict, cpl: list, ipl: list) tuple[source]

Write file that contains the ode-equations for the Model Returns the list R that contains the initial condition for each reservoir

Parameters:
  • Model – Model handle

  • R – list of floats with the initial conditions for each reservoir

  • icl – dict of reservoirs that have actual fluxes

  • cpl – list of reservoirs that have no fluxes but are computed based on other reservoirs

  • ipl – list of reservoir that do not change in concentration

esbmtk.ode_backend.write_reservoir_equations(eqs, M: Model, rel: str, ind2: str, ind3: str) str[source]

Loop over reservoirs and their fluxes to build the reservoir equation

Parameters:
  • eqs – equation file handle

  • rel – string with reservoir names used in return function. Note that these are the reervoir names as used by the equations and not the reservoir names used by esbmtk. E.g., M1.R1.O2 will be M1_R1_O2,

  • ind2 – string with indentation offset

  • ind3 – string with indentation offset

Returns:

rel = updated list of reservoirs names

esbmtk.ode_backend.write_reservoir_equations_with_isotopes(eqs, M: Model, rel: str, ind2: str, ind3: str) str[source]

Loop over reservoirs and their fluxes to build the reservoir equation

esbmtk.post_processing module

esbmtk.post_processing.carbonate_system_1_pp(box_names: SpeciesGroup) None[source]

Calculates and returns various carbonate species based on previously calculated Hplus, TA, and DIC concentrations.

LIMITATIONS: - Assumes all concentrations are in mol/kg - Assumes your Model is in mol/kg ! Otherwise, DIC and TA updating will not be correct.

Calculations are based off equations from: Boudreau et al., 2010, https://doi.org/10.1029/2009GB003654 Follows, 2006, doi:10.1016/j.ocemod.2005.05.004

Parameters:

rg – A reservoirgroup object with initialized carbonate system

esbmtk.post_processing.carbonate_system_2_pp(bn: Reservoir | list, export_fluxes: float | list, zsat_min: float = 200, zmax: float = 6000) None[source]

Calculates and returns the fraction of the carbonate rain that is dissolved an returned back into the ocean.

Parameters:
  • rg – Reservoir, e.g., M.D_b

  • export – export flux in mol/year

  • zsat_min – depth of mixed layer

  • zmax – depth of lookup table

returns:

DIC_burial, DIC_burial_l, Hplus, zsnow

Additionally, it calculates the following critical depth intervals:

zsat: top of lysocline zcc: carbonate compensation depth

LIMITATIONS: - Assumes all concentrations are in mol/kg - Assumes your Model is in mol/kg ! Otherwise, DIC and TA updating will not be correct.

Calculations are based off equations from: Boudreau et al., 2010, https://doi.org/10.1029/2009GB003654 Follows, 2006, doi:10.1016/j.ocemod.2005.05.004

esbmtk.post_processing.gas_exchange_fluxes(liquid_reservoir: Species, gas_reservoir: GasReservoir, pv: str)[source]

Calculate gas exchange fluxes for a given reservoir

Parameters:
  • liquid_reservoir – Species handle

  • gas_reservoir – Species handle

  • pv – piston velocity as string e.g., “4.8 m/d”

Returns:

esbmtk.processes module

esbmtk: A general purpose Earth Science box model toolkit Copyright (C), 2020-2021 Ulrich G. Wortmann

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

esbmtk.processes.gas_exchange(gas_c: float | tuple, liquid_c: float | tuple, gas_aq: float, p: tuple) float | tuple[source]

Calculate the gas exchange flux across the air sea interface for co2 including isotope effects.

Parameters:
  • gas_c (float | tuple) – gas concentration in atmosphere

  • liquid_c (float | tuple) – reference species in liquid phase, e.g., DIC

  • gas_aq (float) – dissolved gas concentration, e.g., CO2aq

  • p (tuple) – parameters, see init_gas_exchange

Returns:

  • float | tuple – gas flux across the air/sea interface

  • Note that the sink delta is co2aq as returned by the carbonate VR

  • this equation is for mmol but esbmtk uses mol, so we need to

  • multiply by 1E3

  • The Total flux across interface dpends on the difference in either

  • concentration or pressure the atmospheric pressure is known, as gas_c, and

  • we can calculate the equilibrium pressure that corresponds to the dissolved

  • gas in the water as [CO2]aq/beta.

  • Conversely, we can convert the the pCO2 into the amount of dissolved CO2 =

  • pCO2 * beta

  • The h/c ratio in HCO3 estimated via h/c in DIC. Zeebe writes C12/C13 ratio

  • but that does not work. the C13/C ratio results however in -8 permil

  • offset, which is closer to observations

esbmtk.processes.init_gas_exchange(c: Species2Species)[source]

Create an ExternalCode instance for gas exchange reactions

Parameters:

c (Species2Species) – connection instance

esbmtk.processes.init_weathering(c: Species2Species, pco2: float, pco2_0: float | str | Q_, area_fraction: float, ex: float, f0: float | str | Q_)[source]

Creates a new external code instance

Parameters:
  • c – Species2Species

  • pco2 – float current pco2

  • pco2_0 – float reference pco2

  • ex – exponent

Area_fraction:

float area/total area

F0:

flux at pco2_0

esbmtk.processes.weathering(c_pco2: float | list[float], p: tuple) float | tuple[source]

Calculate weathering as a function of pCO2

Parameters:
  • c_pco2 (float | list[float]) – current pCO2 concentration

  • p (tuple) – a tuple with the following entries: pco2_0 = reference pCO2 area_fraction = fraction of total surface area ex = exponent used in the equation f0 = flux at the reference value isotopes = True/False

Returns:

  • float | tuple – a float or list value for the weathering flux

  • Explanation

  • ———–

  • If the model uses isotopes, the function expects the concentration

  • values for hthe total mass and the light isotope as a list, and

  • will simiraly return the flux as a list of total flux and flux of

  • the light isotope.

  • The flux itself is calculated as – F_w = area_fraction * f0 * (pco2/pco2_0)**ex

esbmtk.sealevel module

esbmtk.sealevel

Classes which provide access to hypsometric data

esbmtk: A general purpose Earth Science box model toolkit Copyright (C), 2020 Ulrich G. Wortmann

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

esbmtk.sealevel.get_box_geometry_parameters(box, fraction=1) None[source]

Calculate box volume and area from the data in box.

Parameters:

box – list or dict with the geometry parameters

Fraction:

0 to 1 to specify a fractional part (i.e., Atlantic)

If box is a list the first entry is the upper depth datum, the second entry is the lower depth datum, and the third entry is the total ocean area. E.g., to specify the upper 200 meters of the entire ocean, you would write:

geometry=[0,-200,3.6e14]

the corresponding ocean volume will then be calculated by the calc_volume method in this case the following instance variables will also be set:

  • self.volume in model units (usually liter)

  • self.are:a surface area in m^2 at the upper bounding surface

  • self.sed_area: area of seafloor which is intercepted by this box.

  • self.area_fraction: area of seafloor which is intercepted by this relative to the total ocean floor area

It is also possible to specify volume and area explicitly. In this case provide a dictionary like this:

box = {"area": "1e14 m**2", # surface area in m**2
       "volume": "3e16 m**3", # box volume in m**3
       "ta": "4e16 m**2", # reference area
      }
class esbmtk.sealevel.hypsometry(**kwargs)[source]

Bases: esbmtkBase

A class to provide hypsometric data for the depth interval between -6000 to 1000 meter (relative to sealevel)

Invoke as:

hyspometry(name=”hyp”)

area(elevation: int) float[source]

Calculate the ocean area at a given depth

Parameters:

elevation (int) – Elevation datum in meters

Returns:

area in m^2

Return type:

float

area_dz(u: float, l: float) float[source]

calculate the area between two elevation datums

Parameters:
  • u (float) – upper elevation datum in meters (relative to sealevel)

  • l (float) – lower elevation datum relative to sealevel

Returns:

area in m^2

Return type:

float

Raises:

ValueError – if elevation datums are outside the defined interval

get_lookup_table_area() ndarray[Any, dtype[float64]][source]

Return the area values between 0 and max_depth as 1-D array

get_lookup_table_area_dz() ndarray[Any, dtype[float64]][source]

Return the are_dz values between 0 and max_depth as 1-D array

read_data() None[source]

Read the hypsometry data from a pickle file. If the pickle file is missing, create it from the csv data

save the hypsometry data as a numpy array with elevation, area, and area_dz in self.hypdata

show_data()[source]

Provide a diagnostic graph that shows the hypsometric data use by ESBMTK

volume(u: float, l: float) float[source]

Calculate the area between two elevation datums

Parameters:
  • u (float) – upper elevation datum in meters (relative to sealevel)

  • l (float) – lower elevation datum relative to sealevel

Returns:

volume in m^3

Return type:

float

Raises:

ValueError – if elevation datums are outside the defined interval

esbmtk.seawater module

esbmtk: A general purpose Earth Science box model toolkit Copyright (C), 2020-2021 Ulrich G. Wortmann

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

class esbmtk.seawater.SeawaterConstants(**kwargs: dict[str, str])[source]

Bases: esbmtkBase

Provide basic seawater properties as a function of T, P and Salinity. Since we cannot know if TA and DIC have already been specified, creating the instance uses standard seawater composition. Updating/Setting TA & DIC does not recalculate these values after initialization, unless you explicitly call the update_parameters() method.

Example:

Seawater(name="SW",
         register=M # model handle
         temperature = optional in C, defaults to 25,
         salinity  = optional in psu, defaults to 35,
         pressure = optional, defaults to 0 bars = 1atm,
         pH = 8.1, # optional
        )

Results are always in mol/kg

Acess the values “dic”, “ta”, “ca”, “co2”, “hco3”, “co3”, “boron”, “boh4”, “boh3”, “oh”, “ca2”, “so4”,”hplus”, as SW.co3 etc.

This method also provides “K0”, “K1”, “K2”, “KW”, “KB”, “Ksp”, “Ksp0”, “KS”, “KF” and their corresponding pK values, as well as the density for the given (P/T/S conditions)

useful methods:

SW.show() will list values

After initialization this class provides access to each value the following way

instance_name.variable_name

Since this class is just a frontend to PyCO2SYS, it is easy to add parameters that are supported in PyCO2SYS. See the update_parameter() method.

calc_solubility_term(S, T, A1, A2, A3, A4, B1, B2, B3) float[source]
co2_solubility_constant() None[source]

Calculate the solubility of CO2 at a given temperature and salinity.

The value for K0 is taken from pyCO2sys which is in mol/kg-SW/atm esbmtk uses mol/(t atm). pyCO2sys follows Weiss, R. F., Marine Chemistry 2:203-215, 1974.

get_density(S, TC, P) float[source]

Calculate seawater density as function of temperature, salinity and pressure

Parameters:
  • S – salinity in PSU

  • TC – temp in C

  • P – pressure in bar

Returns rho:

in kg/m**3

o2_solubility_constant() None[source]

Calculate the solubility of CO2 at a given temperature and salinity. Coefficients after Sarmiento and Gruber 2006 which includes corrections for non ideal gas behavior

Parameters Ai & Bi from Tab 3.2.2 in Sarmiento and Gruber 2006

The result is in mol/(1000kg atm)

show() None[source]

Printout constants. Units are mol/kg or (mol**2/kg for doubly charged ions

update_parameters(**kwargs: dict) None[source]

Update values if necessary

water_vapor_partial_pressure() None[source]

Calculate the water vapor partial pressure at sealevel (1 atm) as a function of temperature and salinity. Eq. Weiss and Price 1980 doi:10.1016/0304-4203(80)90024-9

Since we assume that we only use this expression at sealevel, we drop the pressure term

The result is in p/1atm (i.e., a percentage)

esbmtk.species_definitions module

esbmtk: A general purpose Earth Science box model toolkit Copyright (C), 2020 Ulrich G. Wortmann

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

esbmtk.species_definitions.Boron(model)[source]
esbmtk.species_definitions.Carbon(model)[source]

Some often used definitions

esbmtk.species_definitions.Hydrogen(model)[source]
esbmtk.species_definitions.Nitrogen(model)[source]
esbmtk.species_definitions.Oxygen(model: Model) None[source]

Common Properties of Oxygen

Parameters:

model (Model) – Model instance

esbmtk.species_definitions.Phosphor(model)[source]
esbmtk.species_definitions.Sulfur(model)[source]
esbmtk.species_definitions.misc_variables(model)[source]

esbmtk.utility_functions module

esbmtk: A general purpose Earth Science box model toolkit Copyright (C), 2020 Ulrich G. Wortmann

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

exception esbmtk.utility_functions.ScaleError(message)[source]

Bases: Exception

esbmtk.utility_functions.add_to(l, e)[source]

add element e to list l, but check if the entry already exist. If so, throw exception. Otherwise add

esbmtk.utility_functions.build_concentration_dicts(cd: dict, bg: dict) dict[source]

Build a dict which can be used by create_reservoirs

Parameters:
  • bg – dict where the box_names are dict keys.

  • cd – dictionary

with the following format:

cd = {
     # species: [concentration, isotopes]
     PO4: [Q_("2.1 * umol/liter"), False],
     DIC: [Q_("2.1 mmol/liter"), False],
    }

This function returns a new dict in the following format

# box_names: [concentrations, isotopes] d= {“bn”: [{PO4: .., DIC: ..},{PO4:False, DIC:False}]}

esbmtk.utility_functions.build_ct_dict(d: dict, p: dict) dict[source]

build a connection dictionary from a dict containing connection keys, and a dict containing connection properties. This is most useful for connections which a characterized by a fixed rate but apply to many species. E.g., mixing fluxes in a complex model etc.

esbmtk.utility_functions.calc_volumes(bg: dict, M: any, h: any) list[source]

Calculate volume contained in a given depth interval bg is a dictionary in the following format:

bg={
    "hb": (0.1, 0, 200),
    "sb": (0.9, 0, 200),
   }

where the key must be a valid box name, the first entry of the list denoted the areal extent in percent, the second number is upper depth limit, and last number is the lower depth limit.

M must be a model handle h is the hypsometry handle

The function returns a list with the corresponding volumes

esbmtk.utility_functions.check_for_quantity(quantity, unit)[source]

check if keyword is quantity or string an convert as necessary

Parameters:
  • quantity (str | quantity | float | int) – e.g., “12 m/s”, or 12,

  • unit (str) – desired unit for keyword, e.g., “m/s”

Returns:

Returns a Quantity

Return type:

Q_

Raises:

ValueError – if keywword is neither number, str or quantity

esbmtk.utility_functions.convert_to_lists(d: dict, l: int) dict[source]

expand mixed dict entries (i.e. list and single value) such that they are all lists of equal length

esbmtk.utility_functions.create_bulk_connections(ct: dict, M: Model, mt: int = '1:1') dict[source]

Create connections from a dictionary. The dict can have the following keys following format:

mt = mapping type. See below for explanation

# na: names, tuple or str. If lists, all list elements share the same properties # sp: species list or species # ty: type, str # ra: rate, Quantity # sc: scale, Number # re: reference, optional # al: alpha, optional # de: delta, optional # bp: bypass, see scale_with_flux # si: signal # mx: True, optional defaults to False. If set, it will create forward and backward fluxes (i.e. mixing)

There are 6 different cases how to specify connections

Case 1 One connection, one set of parameters

ct1 = {“sb2hb”: {“ty”: “scale”, ‘ra’….}}

Case 2 One connection, one set of instructions, one subset with multiple parameters

This will be expanded to create connections for each species ct2 = {“sb2hb”: {“ty”: “scale”, “sp”: [“a”, “b”]}}

Case 3 One connection complete set of multiple characters. Similar to case 2,

but now all parameters are given explicitly ct3 = {“sb2hb”: {“ty”: [“scale”, “scale”], “sp”: [“a”, “b”]}}

Case 4 Multiple connections, one set of parameters. This will create

identical connection for “sb2hb” and “ib2db” ct4 = {(“sb2hb”, “ib2db”): {“ty”: “scale”, ‘ra’: …}}

Case 5 Multiple connections, one subset of multiple set of parameters. This wil
create a connection for species ‘a’ in sb2hb and with species ‘b’ in ib2db

ct5 = {(“sb2hb”, “ib2db”): {“ty”: “scale”, “sp”: [“a”, “b”]}}

Case 6 Multiple connections, complete set of parameters of multiple parameters

Same as case 5, but now all parameters are specified explicitly ct6 = {(“sb2hb”, “ib2db”): {“ty”: [“scale”, “scale”], “sp”: [“a”, “b”]}}

The default interpretation for cases 5 and 6 is that each list entry corresponds to connection. However, sometimes we want to create multiple connections for multiple entries. In this case provide the mt=’1:N’ parameter which will create a connection for each species in each connection group. See the below example.

It is easy to shoot yourself in the foot. It is best to try the above first with some simple examples, e.g.,

from esbmtk import expand_dict ct2 = {“sb2hb”: {“ty”: “scale”, “sp”: [“a”, “b”]}}

It is best to use the show_dict function to verify that your input dictionary produces the correct results!

esbmtk.utility_functions.create_connection(n: str, p: dict, M: Model) None[source]

called by create_bulk_connections in order to create a connection group It is assumed that all rates are in liter/year or mol per year. This may not be what you want or need.

Parameters:
  • n – a connection key. if the mix flag is given interpreted as mixing a connection between sb and db and thus create connections in both directions

  • p – a dictionary holding the connection properties

  • M – the model handle

esbmtk.utility_functions.create_reservoirs(box_dict: dict, ic_dict: dict, M: any) dict[source]

boxes are defined by area and depth interval here we use an ordered dictionary to define the box geometries. The next column is temperature in deg C, followed by pressure in bar the geometry is [upper depth datum, lower depth datum, area percentage]

Parameters:

bn – dictionary with box parameters,

e.g.:

box_dict: dict = {  # name: [[geometry], T, P]
            "sb": {"g": [0, 200, 0.9], "T": 20, "P": 5},
            "ib": {"g": [200, 1200, 1], "T": 10, "P": 100},
           }
Parameters:

ic – dictionary with species default values.

ic is used to set up initial conditions. Here we use shortcut and use the same conditions in each box. If you need box specific initial conditions use the output of build_concentration_dicts as starting point, e.g.,:

ic_dict: dict = { # species: concentration, Isotopes, delta, f_only
             PO4: [Q_("2.1 * umol/liter"), False, 0, False],
             DIC: [Q_("2.1 mmol/liter"), False, 0, False],
             ALK: [Q_("2.43 mmol/liter"), False, 0, False],
         }
Parameters:

M – Model object handle

esbmtk.utility_functions.data_summaries(M: Model, species_names: list, box_names: list, register_with='None') list[source]

Group results by species and Reservoirs

Parameters:
  • M – model instance

  • species_names – list of species instances

  • box_names – list of Reservoir instances

  • register_with – defaults to M

Returns pl:

a list of datafield instance to be plotted

esbmtk.utility_functions.debug(func)[source]

Print the function signature and return value

esbmtk.utility_functions.dict_alternatives(d: dict, e: str, a: str) any[source]

The =dict_alternatives= function takes a dictionary =d=, an expression =e=, and an alternative expression =a=. It returns the value associated with either =a= or =e= in the dictionary =d=.

Parameters:
  • d – A dictionary.

  • e – The first expression to check.

  • a – The alternative expression to check.

Returns r:

The value associated with either =a= or =e= in the dictionary =d=.

Raises:

ValueError – If neither =a= nor =e= are found in the dictionary.

esbmtk.utility_functions.expand_dict(d: dict, mt: str = '1:1') int[source]

Determine dict structure

in case we have mutiple connections with mutiple species, the default action is to map connections to species (t = ‘1:1’). If you rather want to create mutiple connections (one for each species) in each connection set t = ‘1:N’

esbmtk.utility_functions.find_matching_fluxes(l: list, filter_by: str, exclude: str) list[source]

Loop over all reservoir in l, and extract the names of all fluxes which match the filter string. Return the list of names (not objects!)

esbmtk.utility_functions.find_matching_strings(s: str, fl: list[str]) bool[source]

test if all elements of fl occur in s. Return True if yes, otherwise False

esbmtk.utility_functions.gen_dict_entries(M: Model, **kwargs)[source]

Find all fluxes that contain the reference string, and create a new Species2Species instance that connects the flux matching ref_id, with a flux matching target_id. The function will a tuple containig the new connection keys that can be used by the create bulk_connection() function. The second return value is a list containing the reference fluxes.

The optional inverse parameter, can be used where in cases where the flux direction needs to be reversed, i.e., the returned key will not read sb_to_dbPOM, but db_to_sb@POM

Parameters:
  • M – Model or list

  • kwargs – keyword dictionary, known keys are ref_id, and raget_id, inverse

Return f_list:

List of fluxes that match ref_id

Return k_tuples:

tuple of connection keys

esbmtk.utility_functions.get_connection_keys(f_list: set, ref_id: str, target_id: str, inverse: bool, exclude: str) list[str][source]

extract connection keys from set of flux names, replace ref_id with target_id so that the key can be used in create_bulk_connnections()

Parameters:
  • f_list – a set with flux objects

  • ref_id – string with the reference id

  • target_id – string with the target_id

  • inverse – Bool, optional, defaults to false

Return cnc_l:

a list of connection keys (str)

The optional inverse parameter, can be used where in cases where the flux direction needs to be reversed, i.e., the returned key will not read sb2db@POM, but db2s@POM

esbmtk.utility_functions.get_delta(l: ndarray[Any, dtype[float64]], h: ndarray[Any, dtype[float64]], r: float) ndarray[Any, dtype[float64]][source]

Calculate the delta from the mass of light and heavy isotope

Parameters:
  • l – light isotope mass/concentration

  • h – heavy isotope mass/concentration

  • r – reference ratio

:return : delta

esbmtk.utility_functions.get_delta_from_concentration(c, l, r)[source]

Calculate the delta from the mass of light and heavy isotope

Parameters:
  • c – total mass/concentration

  • l – light isotope mass/concentration

  • r – reference ratio

esbmtk.utility_functions.get_delta_h(R) float[source]

Calculate the delta of a flux or reservoir

Parameters:

R – Species or Flux handle

returns d as vector of delta values R.c = total concentration R.l = concentration of the light isotope

esbmtk.utility_functions.get_imass(m: float, d: float, r: float) [<class 'float'>, <class 'float'>][source]

Calculate the isotope masses from bulk mass and delta value. Arguments are m = mass, d= delta value, r = abundance ratio species

esbmtk.utility_functions.get_l_mass(m: float, d: float, r: float) float[source]
Parameters:
  • m – mass or concentration

  • d – delta value

  • r – isotopic reference ratio

return mass or concentration of the light isotopeb

esbmtk.utility_functions.get_longest_dict_entry(d: dict) int[source]

Get length of each item in the connection dict

esbmtk.utility_functions.get_name_only(o: any) any[source]

Test if item is an esbmtk type. If yes, extract the name

esbmtk.utility_functions.get_new_ratio_from_alpha(ref_mass: float, ref_l: float, a: float) [<class 'float'>, <class 'float'>][source]

Calculate the effect of the istope fractionation factor alpha on the ratio between the mass of the light isotope devided by the total mass

Note that alpha needs to be given as fractional value, i.e., 1.07 rather than 70 (i.e., (alpha-1) * 1000

esbmtk.utility_functions.get_object_from_list(name: str, l: list) any[source]

Match a name to a list of objects. Return the object

esbmtk.utility_functions.get_object_handle(res: list, M: Model)[source]

Test if the key is a global reservoir handle or exists in the model namespace

Parameters:
  • res – list of strings, or reservoir handles

  • M – Model handle

esbmtk.utility_functions.get_plot_layout(obj)[source]

Simple function which selects a row, column layout based on the number of objects to display. The expected argument is a reservoir object which contains the list of fluxes in the reservoir

esbmtk.utility_functions.get_reservoir_reference(k: str, M: Model) tuple[source]

Get SpeciesProperties and Species handles

Parameters:
  • k (str) – with the initial flux name, e.g., M_F_A_db_DIC

  • M (Model) – Model handle

Returns:

Species2Species, SpeciesProperties

Return type:

tuple

Raises:

ValueError – If reservoir_name is not of type ConnectionProperties or Species2Species

esbmtk.utility_functions.get_simple_list(l: list) list[source]

return a list which only has the full name rather than all the object properties

esbmtk.utility_functions.get_string_between_brackets(s: str) str[source]

Parse string and extract substring between square brackets

esbmtk.utility_functions.get_sub_key(d: dict, i: int) dict[source]

take a dict which has where the value is a list, and return the key with the n-th value of that list

esbmtk.utility_functions.get_typed_list(data: list) list[source]
esbmtk.utility_functions.insert_into_namespace(name, value, name_space={'NDArrayFloat': numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]], 'ScaleError': <class 'esbmtk.utility_functions.ScaleError'>, '__addmissingdefaults__': <function __addmissingdefaults__>, '__annotations__': {}, '__builtins__': {'ArithmeticError': <class 'ArithmeticError'>, 'AssertionError': <class 'AssertionError'>, 'AttributeError': <class 'AttributeError'>, 'BaseException': <class 'BaseException'>, 'BaseExceptionGroup': <class 'BaseExceptionGroup'>, 'BlockingIOError': <class 'BlockingIOError'>, 'BrokenPipeError': <class 'BrokenPipeError'>, 'BufferError': <class 'BufferError'>, 'BytesWarning': <class 'BytesWarning'>, 'ChildProcessError': <class 'ChildProcessError'>, 'ConnectionAbortedError': <class 'ConnectionAbortedError'>, 'ConnectionError': <class 'ConnectionError'>, 'ConnectionRefusedError': <class 'ConnectionRefusedError'>, 'ConnectionResetError': <class 'ConnectionResetError'>, 'DeprecationWarning': <class 'DeprecationWarning'>, 'EOFError': <class 'EOFError'>, 'Ellipsis': Ellipsis, 'EncodingWarning': <class 'EncodingWarning'>, 'EnvironmentError': <class 'OSError'>, 'Exception': <class 'Exception'>, 'ExceptionGroup': <class 'ExceptionGroup'>, 'False': False, 'FileExistsError': <class 'FileExistsError'>, 'FileNotFoundError': <class 'FileNotFoundError'>, 'FloatingPointError': <class 'FloatingPointError'>, 'FutureWarning': <class 'FutureWarning'>, 'GeneratorExit': <class 'GeneratorExit'>, 'IOError': <class 'OSError'>, 'ImportError': <class 'ImportError'>, 'ImportWarning': <class 'ImportWarning'>, 'IndentationError': <class 'IndentationError'>, 'IndexError': <class 'IndexError'>, 'InterruptedError': <class 'InterruptedError'>, 'IsADirectoryError': <class 'IsADirectoryError'>, 'KeyError': <class 'KeyError'>, 'KeyboardInterrupt': <class 'KeyboardInterrupt'>, 'LookupError': <class 'LookupError'>, 'MemoryError': <class 'MemoryError'>, 'ModuleNotFoundError': <class 'ModuleNotFoundError'>, 'NameError': <class 'NameError'>, 'None': None, 'NotADirectoryError': <class 'NotADirectoryError'>, 'NotImplemented': NotImplemented, 'NotImplementedError': <class 'NotImplementedError'>, 'OSError': <class 'OSError'>, 'OverflowError': <class 'OverflowError'>, 'PendingDeprecationWarning': <class 'PendingDeprecationWarning'>, 'PermissionError': <class 'PermissionError'>, 'ProcessLookupError': <class 'ProcessLookupError'>, 'RecursionError': <class 'RecursionError'>, 'ReferenceError': <class 'ReferenceError'>, 'ResourceWarning': <class 'ResourceWarning'>, 'RuntimeError': <class 'RuntimeError'>, 'RuntimeWarning': <class 'RuntimeWarning'>, 'StopAsyncIteration': <class 'StopAsyncIteration'>, 'StopIteration': <class 'StopIteration'>, 'SyntaxError': <class 'SyntaxError'>, 'SyntaxWarning': <class 'SyntaxWarning'>, 'SystemError': <class 'SystemError'>, 'SystemExit': <class 'SystemExit'>, 'TabError': <class 'TabError'>, 'TimeoutError': <class 'TimeoutError'>, 'True': True, 'TypeError': <class 'TypeError'>, 'UnboundLocalError': <class 'UnboundLocalError'>, 'UnicodeDecodeError': <class 'UnicodeDecodeError'>, 'UnicodeEncodeError': <class 'UnicodeEncodeError'>, 'UnicodeError': <class 'UnicodeError'>, 'UnicodeTranslateError': <class 'UnicodeTranslateError'>, 'UnicodeWarning': <class 'UnicodeWarning'>, 'UserWarning': <class 'UserWarning'>, 'ValueError': <class 'ValueError'>, 'Warning': <class 'Warning'>, 'ZeroDivisionError': <class 'ZeroDivisionError'>, '__build_class__': <built-in function __build_class__>, '__debug__': True, '__doc__': "Built-in functions, types, exceptions, and other objects.\n\nThis module provides direct access to all 'built-in'\nidentifiers of Python; for example, builtins.len is\nthe full name for the built-in function len().\n\nThis module is not normally accessed explicitly by most\napplications, but can be useful in modules that provide\nobjects with the same name as a built-in value, but in\nwhich the built-in of that name is also needed.", '__import__': <built-in function __import__>, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__name__': 'builtins', '__package__': '', '__spec__': ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>, origin='built-in'), 'abs': <built-in function abs>, 'aiter': <built-in function aiter>, 'all': <built-in function all>, 'anext': <built-in function anext>, 'any': <built-in function any>, 'ascii': <built-in function ascii>, 'bin': <built-in function bin>, 'bool': <class 'bool'>, 'breakpoint': <built-in function breakpoint>, 'bytearray': <class 'bytearray'>, 'bytes': <class 'bytes'>, 'callable': <built-in function callable>, 'chr': <built-in function chr>, 'classmethod': <class 'classmethod'>, 'compile': <built-in function compile>, 'complex': <class 'complex'>, 'copyright': Copyright (c) 2001-2023 Python Software Foundation. All Rights Reserved.  Copyright (c) 2000 BeOpen.com. All Rights Reserved.  Copyright (c) 1995-2001 Corporation for National Research Initiatives. All Rights Reserved.  Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. All Rights Reserved., 'credits':     Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands     for supporting Python development.  See www.python.org for more information., 'delattr': <built-in function delattr>, 'dict': <class 'dict'>, 'dir': <built-in function dir>, 'divmod': <built-in function divmod>, 'enumerate': <class 'enumerate'>, 'eval': <built-in function eval>, 'exec': <built-in function exec>, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'filter': <class 'filter'>, 'float': <class 'float'>, 'format': <built-in function format>, 'frozenset': <class 'frozenset'>, 'getattr': <built-in function getattr>, 'globals': <built-in function globals>, 'hasattr': <built-in function hasattr>, 'hash': <built-in function hash>, 'help': Type help() for interactive help, or help(object) for help about object., 'hex': <built-in function hex>, 'id': <built-in function id>, 'input': <built-in function input>, 'int': <class 'int'>, 'isinstance': <built-in function isinstance>, 'issubclass': <built-in function issubclass>, 'iter': <built-in function iter>, 'len': <built-in function len>, 'license': Type license() to see the full license text, 'list': <class 'list'>, 'locals': <built-in function locals>, 'map': <class 'map'>, 'max': <built-in function max>, 'memoryview': <class 'memoryview'>, 'min': <built-in function min>, 'next': <built-in function next>, 'object': <class 'object'>, 'oct': <built-in function oct>, 'open': <built-in function open>, 'ord': <built-in function ord>, 'pow': <built-in function pow>, 'print': <built-in function print>, 'property': <class 'property'>, 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'range': <class 'range'>, 'repr': <built-in function repr>, 'reversed': <class 'reversed'>, 'round': <built-in function round>, 'set': <class 'set'>, 'setattr': <built-in function setattr>, 'slice': <class 'slice'>, 'sorted': <built-in function sorted>, 'staticmethod': <class 'staticmethod'>, 'str': <class 'str'>, 'sum': <built-in function sum>, 'super': <class 'super'>, 'tuple': <class 'tuple'>, 'type': <class 'type'>, 'vars': <built-in function vars>, 'zip': <class 'zip'>}, '__cached__': '/home/docs/checkouts/readthedocs.org/user_builds/esbmtk/checkouts/latest/docs/../src/esbmtk/__pycache__/utility_functions.cpython-311.pyc', '__checkkeys__': <function __checkkeys__>, '__checktypes__': <function __checktypes__>, '__doc__': '\n     esbmtk: A general purpose Earth Science box model toolkit\n     Copyright (C), 2020 Ulrich G. Wortmann\n\n     This program is free software: you can redistribute it and/or modify\n     it under the terms of the GNU General Public License as published by\n     the Free Software Foundation, either version 3 of the License, or\n     (at your option) any later version.\n\n     This program is distributed in the hope that it will be useful,\n     but WITHOUT ANY WARRANTY; without even the implied warranty of\n     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n     GNU General Public License for more details.\n\n     You should have received a copy of the GNU General Public License\n     along with this program.  If not, see <https://www.gnu.org/licenses/>.\n', '__file__': '/home/docs/checkouts/readthedocs.org/user_builds/esbmtk/checkouts/latest/docs/../src/esbmtk/utility_functions.py', '__find_flux__': <function __find_flux__>, '__loader__': <_frozen_importlib_external.SourceFileLoader object>, '__name__': 'esbmtk.utility_functions', '__package__': 'esbmtk', '__spec__': ModuleSpec(name='esbmtk.utility_functions', loader=<_frozen_importlib_external.SourceFileLoader object>, origin='/home/docs/checkouts/readthedocs.org/user_builds/esbmtk/checkouts/latest/docs/../src/esbmtk/utility_functions.py'), 'add_to': <function add_to>, 'annotations': _Feature((3, 7, 0, 'beta', 1), None, 16777216), 'build_concentration_dicts': <function build_concentration_dicts>, 'build_ct_dict': <function build_ct_dict>, 'calc_volumes': <function calc_volumes>, 'check_for_quantity': <function check_for_quantity>, 'convert_to_lists': <function convert_to_lists>, 'create_bulk_connections': <function create_bulk_connections>, 'create_connection': <function create_connection>, 'create_reservoirs': <function create_reservoirs>, 'data_summaries': <function data_summaries>, 'debug': <function debug>, 'dict_alternatives': <function dict_alternatives>, 'expand_dict': <function expand_dict>, 'find_matching_fluxes': <function find_matching_fluxes>, 'find_matching_strings': <function find_matching_strings>, 'functools': <module 'functools' from '/home/docs/.asdf/installs/python/3.11.6/lib/python3.11/functools.py'>, 'gen_dict_entries': <function gen_dict_entries>, 'get_connection_keys': <function get_connection_keys>, 'get_delta': CPUDispatcher(<function get_delta>), 'get_delta_from_concentration': <function get_delta_from_concentration>, 'get_delta_h': <function get_delta_h>, 'get_imass': <function get_imass>, 'get_l_mass': CPUDispatcher(<function get_l_mass>), 'get_longest_dict_entry': <function get_longest_dict_entry>, 'get_name_only': <function get_name_only>, 'get_new_ratio_from_alpha': CPUDispatcher(<function get_new_ratio_from_alpha>), 'get_object_from_list': <function get_object_from_list>, 'get_object_handle': <function get_object_handle>, 'get_plot_layout': <function get_plot_layout>, 'get_reservoir_reference': <function get_reservoir_reference>, 'get_simple_list': <function get_simple_list>, 'get_string_between_brackets': <function get_string_between_brackets>, 'get_sub_key': <function get_sub_key>, 'get_typed_list': <function get_typed_list>, 'insert_into_namespace': <function insert_into_namespace>, 'is_name_in_list': <function is_name_in_list>, 'list_fluxes': <function list_fluxes>, 'logging': <module 'logging' from '/home/docs/.asdf/installs/python/3.11.6/lib/python3.11/logging/__init__.py'>, 'make_dict': <function make_dict>, 'map_units': <function map_units>, 'njit': <function njit>, 'np': <module 'numpy' from '/home/docs/checkouts/readthedocs.org/user_builds/esbmtk/envs/latest/lib/python3.11/site-packages/numpy/__init__.py'>, 'npt': <module 'numpy.typing' from '/home/docs/checkouts/readthedocs.org/user_builds/esbmtk/envs/latest/lib/python3.11/site-packages/numpy/typing/__init__.py'>, 'phc': <function phc>, 'plot_geometry': <function plot_geometry>, 'plt': <module 'matplotlib.pyplot' from '/home/docs/checkouts/readthedocs.org/user_builds/esbmtk/envs/latest/lib/python3.11/site-packages/matplotlib/pyplot.py'>, 'register_new_flux': <function register_new_flux>, 'register_new_reservoir': <function register_new_reservoir>, 'register_return_values': <function register_return_values>, 'register_user_function': <function register_user_function>, 'reverse_key': <function reverse_key>, 'rmtree': <function rmtree>, 'set_y_limits': <function set_y_limits>, 'show_data': <function show_data>, 'show_dict': <function show_dict>, 'sort_by_type': <function sort_by_type>, 'split_key': <function split_key>, 'summarize_results': <function summarize_results>, 'tp': <module 'typing' from '/home/docs/.asdf/installs/python/3.11.6/lib/python3.11/typing.py'>})[source]
esbmtk.utility_functions.is_name_in_list(n: str, l: list) bool[source]

Test if an object name is part of the object list

esbmtk.utility_functions.list_fluxes(self, name, i) None[source]

Echo all fluxes in the reservoir to the screen

esbmtk.utility_functions.make_dict(keys: list, values: list) dict[source]

Create a dictionary from a list and value, or from two lists

esbmtk.utility_functions.map_units(obj: any, v: any, *args) float[source]

parse v to see if it is a string. if yes, map to quantity. parse v to see if it is a quantity, if yes, map to model units and extract magnitude, assign mangitude to return value if not, assign value to return value

Parameters:
  • obj – connection object

  • v – input string/number/quantity

Args:

list of model base units

Returns:

number

Raises:

ScaleError – if input cannot be mapped to a model unit

esbmtk.utility_functions.phc(c: float) float[source]

Calculate concentration as pH. c can be a number or numpy array

Parameters:

c (float) – H+ concentration

Returns:

pH value

Return type:

float

esbmtk.utility_functions.plot_geometry(noo: int)[source]

Define plot geometry based on number of objects to plot

esbmtk.utility_functions.register_new_flux(rg, dict_key, dict_value) list[source]

Register a new flux object with a Species2Species instance

Parameters:
  • rg (Species | Reservoir) – instance to register with

  • dict_key (str) – E.g., “M.A_db.DIC”

  • dict_value (str) – id value, e.g., “db_cs2”

Returns:

list of Flux instances

Return type:

list

esbmtk.utility_functions.register_new_reservoir(r, sp, v)[source]

Register a new reservoir

esbmtk.utility_functions.register_return_values(ef: ExternalFunction, rg) None[source]

Register the return values of an external function instance

Parameters:
  • ec (ExternalFunction) – ExternalFunction Instance

  • rg (Reservoir | Species) – The Resevoir or Reservoirgroup the external function is associated with

Raises:
  • ValueError – If the return value type is undefined

  • Check the return values of external function instances,

  • and create the necessary reservoirs, fluxes, or connections

  • if they are missing.

  • These fluxes are not associated with a connection Object

  • so we register the source/sink relationship with the

  • reservoir they belong to.

  • This fails for GasReservoir since they can have a 1:many

  • relatioship. The below is a terrible hack, it would be

  • better to express this with several connection

  • objects, rather than overloading the source attribute of the

  • GasReservoir class.

esbmtk.utility_functions.register_user_function(M: Model, lib_name: str, func_name: str | list) None[source]

Register user supplied library and function with the model

Parameters:
  • M (Model) – Model handle

  • lib_name (str) – name of python file that contains the function

  • func_name (str | list) – Name of one or more user supplied function(s)

esbmtk.utility_functions.reverse_key(key: str) str[source]

reverse a connection key e.g., sb2db@POM becomes db2sb@POM

esbmtk.utility_functions.rmtree(f) None[source]

Delete file, of file is directorym delete all files in

Parameters:

f – pathlib path object

esbmtk.utility_functions.set_y_limits(ax: Axes, obj: any) None[source]

Prevent the display or arbitrarily small differences

esbmtk.utility_functions.show_data(self, **kwargs) None[source]

Print the 3 lines of the data starting with index

Optional arguments:

index :int = 0 starting index indent :int = 0 indentation

esbmtk.utility_functions.show_dict(d: dict, mt: str = '1:1') None[source]

show dict entries in an organized manner

esbmtk.utility_functions.sort_by_type(l: list, t: list, m: str) list[source]

divide a list by type into new lists. This function will return a list and it is up to the calling code to unpack the list

l is list with various object types t is a list which contains the object types used for sorting m is a string for the error function

esbmtk.utility_functions.split_key(k: str, M: any) any | str[source]

split the string k with letters _to_, and test if optional id string is present

esbmtk.utility_functions.summarize_results(M: Model)[source]

Summarize all model results at t_max into a hirarchical dictionary, where values are accessed in the following way:

results[basin_name][level_name][species_name]

e.g., result[“A”][“sb”][“O2”]