CLIMLAB Process objects for advection-diffusion processes of the form

$\begin{split}\frac{\partial}{\partial t} \psi(x,t) &= -\frac{1}{w(x)} \frac{\partial}{\partial x} \left[ w(x) ~ \mathcal{F}(x,t) \right] \\ \mathcal{F} &= U(x) \psi(x) -K(x) ~ \frac{\partial \psi}{\partial x} + F(x)\end{split}$

for a state variable $$\psi(x,t)$$, diffusivity $$K(x)$$ in units of $$x^2 ~ t^{-1}$$, advecting velocity $$U(x)$$ in units of $$x ~ t^{-1}$$, and a prescribed flux F(x) (including boundary conditions) in units of $$\psi ~ x ~ t^{-1}$$.

The prescribed flux $$F(x)$$ defaults to zero everywhere. The user can implement a non-zero boundary flux condition by passing a non-zero array prescribed_flux as input.

$$w(x)$$ is an optional weighting function for the divergence operator on curvilinear grids.

The diffusivity $$K$$ and velocity $$U$$ can be scalars, or optionally vectors specified at grid cell boundaries (so their lengths must be exactly 1 greater than the length of $$x$$).

$$K$$ and $$U$$ can be modified by the user at any time (e.g., after each timestep, if they depend on other state variables).

A fully implicit timestep is used for computational efficiency. Thus the computed tendency $$\frac{\partial \psi}{\partial t}$$ will depend on the timestep.

In addition to the tendency over the implicit timestep, the solver also calculates several diagnostics from the updated state:

• diffusive_flux given by $$-K(x) ~ \frac{\partial \psi}{\partial x}$$ in units of $$[\psi]~[x]$$/s

• advective_flux given by $$U(x) \psi(x)$$ (same units)

• total_flux, the sum of advective, diffusive and prescribed fluxes

• flux_convergence given by the right hand side of the first equation above, in units of $$[\psi]$$/s

This base class can be used without modification for diffusion in Cartesian coordinates ($$w=1$$). Non-uniformly spaced grids are supported.

The state variable $$\psi$$ may be multi-dimensional, but the diffusion will operate along a single dimension only.

Other classes implement the weighting for spherical geometry.

class climlab.dynamics.advection_diffusion.AdvectionDiffusion(K=0.0, U=0.0, diffusion_axis=None, use_banded_solver=False, prescribed_flux=0.0, **kwargs)[source]

A parent class for one dimensional implicit advection-diffusion modules.

Initialization parameters

Parameters
• K (float) – the diffusivity parameter in units of $$\frac{[\textrm{length}]^2}{\textrm{time}}$$ where length is the unit of the spatial axis on which the diffusion is occuring.

• U (float) – Advection velocity in units of $$\frac{[\textrm{length}]}{\textrm{time}}$$

• diffusion_axis (str) – dictionary key for axis on which the diffusion is occuring in process’s domain axes dictionary

• use_banded_solver (bool) – input flag, whether to use scipy.linalg.solve_banded() instead of numpy.linalg.solve() [default: False]

Note

The banded solver scipy.linalg.solve_banded() is faster than numpy.linalg.solve() but only works for one dimensional diffusion.

Object attributes

Additional to the parent class ImplicitProcess following object attributes are generated or modified during initialization:

Variables
• param (dict) – parameter dictionary is extended by diffusivity parameter K (unit: $$\frac{[\textrm{length}]^2}{\textrm{time}}$$)

• use_banded_solver (bool) – input flag specifying numerical solving method (given during initialization)

• diffusion_axis (str) – dictionary key for axis where diffusion is occuring: specified during initialization or output of method _guess_diffusion_axis()

• _advdiffTriDiag (array) – tridiagonal diffusion matrix made by _make_diffusion_matrix() with input self._K_dimensionless

Example

Here is an example showing implementation of a vertical diffusion. It shows that a subprocess can work on just a subset of the parent process state variables.

import climlab
from climlab.dynamics.diffusion import Diffusion
import matplotlib.pyplot as plt

K = 0.5
d = Diffusion(K=K, state = {'Tatm':c.state['Tatm']}, **c.param)

### Integrate & Plot ###

fig = plt.figure( figsize=(6,4))

ax.plot(c.lev, c.state['Tatm'], label='step 0')
c.step_forward()
ax.plot(c.lev, c.state['Tatm'], label='step 1')

ax.invert_xaxis()
ax.set_title('Diffusion subprocess')
ax.set_xlabel('level (mb)')
#ax.set_xticks([])
ax.set_ylabel('temperature (K)')
ax.legend(loc='best')
plt.show()

Attributes
K
U
depth

Depth at grid centers (m)

depth_bounds

Depth at grid interfaces (m)

diagnostics

input

lat

Latitude of grid centers (degrees North)

lat_bounds

Latitude of grid interfaces (degrees North)

lev

Pressure levels at grid centers (hPa or mb)

lev_bounds

Pressure levels at grid interfaces (hPa or mb)

lon

Longitude of grid centers (degrees)

lon_bounds

Longitude of grid interfaces (degrees)

prescribed_flux
timestep

The amount of time over which step_forward() is integrating in unit seconds.

Methods

 add_diagnostic(self, name[, value]) Create a new diagnostic variable called name for this process and initialize it with the given value. add_input(self, name[, value]) Create a new input variable called name for this process and initialize it with the given value. add_subprocess(self, name, proc) Adds a single subprocess to this process. add_subprocesses(self, procdict) Adds a dictionary of subproceses to this process. compute(self) Computes the tendencies for all state variables given current state and specified input. compute_diagnostics(self[, num_iter]) Compute all tendencies and diagnostics, but don’t update model state. declare_diagnostics(self, diaglist) Add the variable names in inputlist to the list of diagnostics. declare_input(self, inputlist) Add the variable names in inputlist to the list of necessary inputs. integrate_converge(self[, crit, verbose]) Integrates the model until model states are converging. integrate_days(self[, days, verbose]) Integrates the model forward for a specified number of days. integrate_years(self[, years, verbose]) Integrates the model by a given number of years. remove_diagnostic(self, name) Removes a diagnostic from the process.diagnostic dictionary and also delete the associated process attribute. remove_subprocess(self, name[, verbose]) Removes a single subprocess from this process. set_state(self, name, value) Sets the variable name to a new state value. set_timestep(self[, timestep, …]) Calculates the timestep in unit seconds and calls the setter function of timestep() step_forward(self) Updates state variables with computed tendencies. to_xarray(self[, diagnostics]) Convert process variables to xarray.Dataset format.
property K
property U
_compute_advdiff_matrix(self)[source]
_implicit_solver(self)[source]
_update_diagnostics(self, newstate)[source]

This method is called each timestep after the new state is computed with the implicit solver. Daughter classes can implement this method to compute any diagnostic quantities using the new state.

property prescribed_flux
class climlab.dynamics.advection_diffusion.Diffusion(K=None, diffusion_axis=None, use_banded_solver=False, **kwargs)[source]

1D diffusion only, with advection set to zero.

Otherwise identical to the parent class AdvectionDiffusion.

Attributes
K
U
depth

Depth at grid centers (m)

depth_bounds

Depth at grid interfaces (m)

diagnostics

input

lat

Latitude of grid centers (degrees North)

lat_bounds

Latitude of grid interfaces (degrees North)

lev

Pressure levels at grid centers (hPa or mb)

lev_bounds

Pressure levels at grid interfaces (hPa or mb)

lon

Longitude of grid centers (degrees)

lon_bounds

Longitude of grid interfaces (degrees)

prescribed_flux
timestep

The amount of time over which step_forward() is integrating in unit seconds.

Methods

 add_diagnostic(self, name[, value]) Create a new diagnostic variable called name for this process and initialize it with the given value. add_input(self, name[, value]) Create a new input variable called name for this process and initialize it with the given value. add_subprocess(self, name, proc) Adds a single subprocess to this process. add_subprocesses(self, procdict) Adds a dictionary of subproceses to this process. compute(self) Computes the tendencies for all state variables given current state and specified input. compute_diagnostics(self[, num_iter]) Compute all tendencies and diagnostics, but don’t update model state. declare_diagnostics(self, diaglist) Add the variable names in inputlist to the list of diagnostics. declare_input(self, inputlist) Add the variable names in inputlist to the list of necessary inputs. integrate_converge(self[, crit, verbose]) Integrates the model until model states are converging. integrate_days(self[, days, verbose]) Integrates the model forward for a specified number of days. integrate_years(self[, years, verbose]) Integrates the model by a given number of years. remove_diagnostic(self, name) Removes a diagnostic from the process.diagnostic dictionary and also delete the associated process attribute. remove_subprocess(self, name[, verbose]) Removes a single subprocess from this process. set_state(self, name, value) Sets the variable name to a new state value. set_timestep(self[, timestep, …]) Calculates the timestep in unit seconds and calls the setter function of timestep() step_forward(self) Updates state variables with computed tendencies. to_xarray(self[, diagnostics]) Convert process variables to xarray.Dataset format.
climlab.dynamics.advection_diffusion._guess_diffusion_axis(process_or_domain)[source]

Scans given process, domain or dictionary of domains for a diffusion axis and returns appropriate name.

In case only one axis with length > 1 in the process or set of domains exists, the name of that axis is returned. Otherwise an error is raised.

Parameters

process_or_domain (Process, _Domain or dict of domains) – input from where diffusion axis should be guessed

Raises

ValueError if more than one diffusion axis is possible.

Returns

name of the diffusion axis

Return type

str