# climlab.surface.turbulent¶

Processes for surface turbulent heat and moisture fluxes

SensibleHeatFlux and LatentHeatFlux implement standard bulk formulae for the turbulent heat fluxes, assuming that the heating or moistening occurs in the lowest atmospheric model level.

Example

Here is an example of setting up a single-column Radiative-Convective model with interactive water vapor and surface latent and sensible heat fluxes.

This example also demonstrates asynchronous coupling: the radiation uses a longer timestep than the other model components:

import numpy as np
import climlab
from climlab import constants as const
# Temperatures in a single column
full_state = climlab.column_state(num_lev=30, water_depth=2.5)
temperature_state = {'Tatm':full_state.Tatm,'Ts':full_state.Ts}
#  Initialize a nearly dry column (small background stratospheric humidity)
q = np.ones_like(full_state.Tatm) * 5.E-6
#  Add specific_humidity to the state dictionary
full_state['q'] = q
#  ASYNCHRONOUS COUPLING -- the radiation uses a much longer timestep
#  The top-level model
model = climlab.TimeDependentProcess(state=full_state,
timestep=const.seconds_per_hour)
#  Radiation coupled to water vapor
specific_humidity=full_state.q,
albedo=0.3,
timestep=const.seconds_per_day
)
#  Convection scheme -- water vapor is a state variable
conv = climlab.convection.EmanuelConvection(state=full_state,
timestep=const.seconds_per_hour)
#  Surface heat flux processes
shf = climlab.surface.SensibleHeatFlux(state=temperature_state, Cd=0.5E-3,
timestep=const.seconds_per_hour)
lhf = climlab.surface.LatentHeatFlux(state=full_state, Cd=0.5E-3,
timestep=const.seconds_per_hour)
#  Couple all the submodels together
print(model)

#  Run the model
model.integrate_years(1)
#  Check for energy balance
print(model.ASR - model.OLR)

class climlab.surface.turbulent.LatentHeatFlux(Cd=0.003, **kwargs)[source]

Bases: climlab.surface.turbulent._SurfaceFlux

Surface turbulent latent heat flux implemented through a bulk aerodynamic formula.

The flux is computed from

$LH = r ~ L ~\rho ~ C_D ~ U \left( q_s - q_a \right)$

where:

• $$L$$ and $$\rho$$ are the latent heat of vaporization and density of air

• $$C_D$$ is a drag coefficient (stored as self.Cd, default value is 3E-3)

• $$U$$ is the near-surface wind speed, stored as self.U, default value is 5 m/s

• $$r$$ is an optional resistance parameter (stored as self.resistance, default value = 1)

The surface specific humidity $$q_s$$ is computed as the saturation specific humidity at the surface temperature self.state['Ts'] and surface pressure self.ps, while the near-surface specific humidity $$q_a$$ is taken as the lowest model level in the field self.q (which must be provided either as a state variable or as input).

Two diagnostics are computed:

• self.LHF gives the sensible heat flux in W/m2.

• self.evaporation gives the evaporation rate in kg/m2/s (or mm/s)

How the tendencies are computed depends on whether specific humidity q is a state variable (i.e. is present in self.state):

• If q is in self.state then the evaporation determines the specific humidity tendency self.tendencies['q']. The water vapor is added to the lowest model level only. Evaporation cools the surface through the surface tendency self.tendencies['Ts']. Air temperature tendencies are zero everywhere.

• If q is not in self.state then we compute an equivalent air temperature tendency for the lowest model layer instead of a specific humidity tendency (i.e. the latent heat flux is applied in the same way as a sensible heat flux).

This process does not apply a tendency to the surface water amount. In the absence of other water processes this implies an infinite water source at the surface (slab ocean).

Attributes
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)

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.
class climlab.surface.turbulent.SensibleHeatFlux(Cd=0.003, **kwargs)[source]

Bases: climlab.surface.turbulent._SurfaceFlux

Surface turbulent sensible heat flux implemented through a bulk aerodynamic formula.

The flux is computed from

$SH = r ~ c_p ~\rho ~ C_D ~ U \left( T_s - T_a \right)$

where:

• $$c_p$$ and $$\rho$$ are the specific heat and density of air

• $$C_D$$ is a drag coefficient (stored as self.Cd, default value is 3E-3)

• $$U$$ is the near-surface wind speed, stored as self.U, default value is 5 m/s

• $$r$$ is an optional resistance parameter (stored as self.resistance, default value = 1)

The surface temperature $$T_s$$ is taken directly from self.state['Ts'], while the near-surface air temperature $$T_a$$ is taken as the lowest model level in self.state['Tatm']

Diagnostic quantity self.SHF gives the sensible heat flux in W/m2.

Temperature tendencies associated with this flux are computed for Ts and for the lowest model level in Tatm. All other tendencies (including air temperature tendencies at other levels) are set to zero.

Attributes
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)

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.