tephpy.calc#

Tephigram-native thermodynamic analysis over metpy.calc (spec §3.3).

Physics is delegated to MetPy; only tephigram-native compositions live here, and everything returns pint quantities on the shared registry (spec §5). Sounding-level functions take a Sounding — constructing one already validates units, monotonic pressure, and dewpoint ≤ temperature — while normand_point() is the one quantity-level function. MetPy stays behind function-local imports so that import tephpy stays light (spec §10 item 10).

Analysis results distinguish “does not exist” from “zero” (spec §6): metpy.calc returns NaN quantities for a missing LFC/EL and 0 J/kg — never NaN — for zero CAPE/CIN, and tephpy passes both through, documented per SoundingIndices field.

Classes#

Profile

One computed parcel ascent, ready to plot (spec §3.3).

SoundingIndices

Derived thermodynamic parameters for one sounding (spec §3.3).

Functions#

normand_point(→ tuple[pint.Quantity, pint.Quantity])

Construct Normand's point — the LCL — for one parcel (spec §3.3).

parcel_path(→ Profile)

Compute a parcel's ascent path over the sounding's span (spec §3.3).

indices(→ SoundingIndices)

Compute the derived thermodynamic parameters (spec §3.3).

Module Contents#

class tephpy.calc.Profile[source]#

One computed parcel ascent, ready to plot (spec §3.3).

Plain plottable data: plot_profile draws it and the shading builders consume it, and neither re-derives the LCL. Construction mirrors Sounding: bare arrays take the units= mapping, fields are dimension-checked quantities on the shared registry, and validation happens at construction.

Attributes:
pressurepint.Quantity

Path pressures, surface-first (strictly decreasing), at least two levels.

temperaturepint.Quantity

Parcel temperatures along the path.

lcl_pressurepint.Quantity

Scalar pressure of the Normand’s point the path actually uses — the corrected one when a correction was requested — inside the path’s pressure span.

lcl_temperaturepint.Quantity

Scalar temperature at that point.

parcelstr

The lifted parcel: "surface" or "mixed-layer".

labelstr or None

Legend text; None means no legend entry.

unitsmapping of str to str, optional

Construction-only (not stored): unit strings for bare-array fields, keyed by field name (spec §5).

pressure: pint.Quantity#
temperature: pint.Quantity#
lcl_pressure: pint.Quantity#
lcl_temperature: pint.Quantity#
parcel: Literal['surface', 'mixed-layer'] = 'surface'#
label: str | None = None#
units: dataclasses.InitVar[collections.abc.Mapping[str, str] | None] = None#
class tephpy.calc.SoundingIndices[source]#

Derived thermodynamic parameters for one sounding (spec §3.3).

Ten scalar quantity fields, each dimension-checked at construction. There is no cross-field validation: NaN fields are answers, not errors — analysis results distinguish “does not exist” (NaN) from “zero” (spec §6).

Attributes:
capepint.Quantity

Convective available potential energy (J/kg); 0 J/kg — never NaN — when the parcel has no positive-buoyancy region.

cinpint.Quantity

Convective inhibition (J/kg, non-positive); 0 J/kg when there is no LFC or no negative-buoyancy region below it.

lcl_pressurepint.Quantity

Pressure of the lifting condensation level the parcel uses (the corrected one when a correction was requested); always defined.

lcl_temperaturepint.Quantity

Temperature at that level; always defined.

lfc_pressurepint.Quantity

Pressure of the level of free convection; NaN when the parcel never becomes positively buoyant.

lfc_temperaturepint.Quantity

Temperature at that level; NaN with lfc_pressure.

el_pressurepint.Quantity

Pressure of the equilibrium level; NaN when it does not exist — including while cape > 0 with the parcel still buoyant at the profile top.

el_temperaturepint.Quantity

Temperature at that level; NaN with el_pressure.

theta_wpint.Quantity

Wet-bulb potential temperature of the lifted parcel, evaluated at the parcel start, so it follows the parcel= option; always defined.

lifted_indexpint.Quantity

Lifted index (a temperature difference at 500 hPa); NaN when the profile tops out below 500 hPa.

unitsmapping of str to str, optional

Construction-only (not stored): unit strings for bare scalar fields, keyed by field name (spec §5).

cape: pint.Quantity#
cin: pint.Quantity#
lcl_pressure: pint.Quantity#
lcl_temperature: pint.Quantity#
lfc_pressure: pint.Quantity#
lfc_temperature: pint.Quantity#
el_pressure: pint.Quantity#
el_temperature: pint.Quantity#
theta_w: pint.Quantity#
lifted_index: pint.Quantity#
units: dataclasses.InitVar[collections.abc.Mapping[str, str] | None] = None#
tephpy.calc.normand_point(pressure: object, temperature: object, dewpoint: object, *, units: collections.abc.Mapping[str, str] | None = None) tuple[pint.Quantity, pint.Quantity][source]#

Construct Normand’s point — the LCL — for one parcel (spec §3.3).

The geometric construction: the dry adiabat through (pressure, temperature) meets the humidity mixing-ratio line through (pressure, dewpoint) at the lifting condensation level. This is always the uncorrected construction; the operational cloud-base correction is parcel_path()’s concern.

Parameters:
pressurepint.Quantity or float

Scalar parcel pressure; a bare value takes the units= mapping.

temperaturepint.Quantity or float

Scalar parcel temperature.

dewpointpint.Quantity or float

Scalar parcel dewpoint; must not exceed temperature (equality — saturation — is physical, and puts Normand’s point at the parcel).

unitsmapping of str to str, optional

Unit strings for bare values, keyed by argument name, e.g. units={"pressure": "hPa", "temperature": "degC"} (spec §5).

Returns:
tuple of pint.Quantity

The scalar (pressure, temperature) of Normand’s point, in hPa and degrees Celsius.

Raises:
TephpyUnitsError

For unit-less bare values, ambiguous or unparsable units, or the wrong dimensionality.

DewpointExceedsTemperatureError

If dewpoint exceeds temperature.

TephpyValidationError

If an argument is not a scalar.

tephpy.calc.parcel_path(snd: tephpy.sounding.Sounding, *, parcel: Literal['surface', 'mixed-layer'] = 'surface', cloud_base_correction: object = None, label: str | None = None) Profile[source]#

Compute a parcel’s ascent path over the sounding’s span (spec §3.3).

Dry adiabat from the parcel start to Normand’s point, then moist adiabat to the profile top. Both legs sample the background moist adiabats’ 5 hPa step, the moist leg is integrated with metpy.calc.moist_lapse(..., reference_pressure=lcl_pressure) — same integrator, same sampling, same anchoring as the background family — and the LCL vertex is spliced in exactly.

Parameters:
sndSounding

The environment sounding; must carry dewpoint.

parcelstr, default: “surface”

The lifted parcel: "surface" starts from the lowest level; "mixed-layer" starts from metpy.calc.mixed_parcel() (its 100 hPa default depth is the operational convention).

cloud_base_correctionpint.Quantity, optional

A pressure-dimension correction added to the LCL pressure, applied only when explicitly requested; the operational -25 mb value lives in tephpy._constants.CLOUD_BASE_CORRECTION. The corrected LCL temperature is re-read from the dry adiabat at the corrected pressure.

labelstr, optional

Legend text for the profile; None means no legend entry.

Returns:
Profile

The parcel path, surface-first, with the LCL it actually uses.

Raises:
MissingDataError

If the sounding has no dewpoint.

ProfileTooShortError

If the profile tops out at or below the LCL the path would use (the corrected one when a correction is requested), or a mixed-layer parcel is requested but the sounding spans less than the mixed-layer depth.

TephpyUnitsError

If cloud_base_correction is not a pressure-dimension quantity.

TephpyValidationError

If the selected parcel start has an undefined (NaN) temperature or dewpoint, or the correction places the LCL below the parcel start.

ValueError

If parcel is not a known option.

tephpy.calc.indices(snd: tephpy.sounding.Sounding, *, parcel: Literal['surface', 'mixed-layer'] = 'surface', cloud_base_correction: object = None) SoundingIndices[source]#

Compute the derived thermodynamic parameters (spec §3.3).

The mechanism: derive the parcel curve on the environment levels under the same parcel-selection and correction rules as parcel_path(), then feed it to the generic metpy.calc functions that take a parcel-profile argument (cape_cin, lfc, el, lifted_index). With the defaults this reduces to plain surface-parcel delegation. The lcl_* fields report the point the path uses (corrected when requested) and theta_w the parcel start, mirroring Profile.

theta_w is computed with wet_bulb_potential_temperature, whose Davies-Jones formulation differs from the moist-adiabat integrator by ≲0.1 °C: the path is drawn by the integrator, the number by the named function (spec §3.3).

Parameters:
sndSounding

The environment sounding; must carry dewpoint.

parcelstr, default: “surface”

The lifted parcel, as for parcel_path().

cloud_base_correctionpint.Quantity, optional

The LCL correction, as for parcel_path().

Returns:
SoundingIndices

The ten derived parameters, with the spec §6 NaN-versus-zero semantics documented per field.

Raises:
MissingDataError

If the sounding has no dewpoint.

ProfileTooShortError

If the profile tops out at or below the LCL the parcel would use, or a mixed-layer parcel is requested but the sounding spans less than the mixed-layer depth.

TephpyUnitsError

If cloud_base_correction is not a pressure-dimension quantity.

TephpyValidationError

If the selected parcel start has an undefined (NaN) temperature or dewpoint, or the correction places the LCL below the parcel start.

ValueError

If parcel is not a known option.