Skip to content

Plume rise

Briggs plume rise for buoyant and momentum sources: BriggsPlumeRise returns Δh(x) from a stack's exit velocity, exit temperature and diameter, and effective_height gives H_eff = H_stack + Δh(x). Pass a BriggsPlumeRise as plume_rise= to plume_concentration or simulate_plume to release the plume at its effective height, differentiably in the stack parameters. Tier I.

plume_rise

Briggs plume rise and the effective release height (implementation in plumax.gauss_plume._src.plume_rise).

BriggsPlumeRise

Bases: Module

Briggs plume rise Δh(x) of a stack plume, from its buoyancy and momentum.

Δh(x) = max(Δh_b(x), Δh_m(x)), with the buoyant and momentum rises of the module docstring.

Algorithm
  1. Fluxes F_b = g v_s d² (T_s − T_a)/(4 T_s), floored at 0, and F_m = v_s² d² T_a/(4 T_s).
  2. Buoyant rise: the 2/3 law 1.6 F_b^{1/3} x^{2/3}/u, capped at the class's final rise.
  3. Momentum rise: the jet law 1.44 d (v_s/u)^{2/3} (x/d)^{1/3}, capped at 3 d v_s/u, and in stable air also at 1.5 (F_m/u)^{1/3} s^{−1/6}.
  4. Take the larger of the two.

Attributes:

Name Type Description
exit_velocity float | Float[Array, '']

Stack exit velocity v_s ≥ 0 [m s⁻¹].

exit_temperature float | Float[Array, '']

Stack gas temperature T_s > 0 [K].

stack_diameter float | Float[Array, '']

Inside stack-top diameter d > 0 [m].

ambient_temperature float | Float[Array, '']

Ambient air temperature T_a > 0 [K].

stability_class str

Pasquill–Gifford class 'A' … 'F'; E and F use the stable formulas with ∂θ/∂z from :data:STABLE_THETA_GRADIENT.

Raises:

Type Description
ParameterError

If the class is not A–F or a parameter is out of range.

Examples:

A hot stack in neutral air: past x_f the rise is the final rise.

>>> import jax.numpy as jnp
>>> rise = BriggsPlumeRise(
...     exit_velocity=10.0, exit_temperature=400.0, stack_diameter=2.0,
...     ambient_temperature=290.0, stability_class="D",
... )
>>> heights = rise(jnp.array([100.0, 5000.0, 20000.0]), wind_speed=5.0)
>>> heights.shape
(3,)
>>> bool(heights[1] == heights[2])
True

A cold, still stack does not rise:

>>> still = BriggsPlumeRise(
...     exit_velocity=0.0, exit_temperature=290.0, stack_diameter=2.0,
...     ambient_temperature=290.0,
... )
>>> still(jnp.array([500.0]), wind_speed=5.0).tolist()
[0.0]

Classes outside A–F are rejected:

>>> BriggsPlumeRise(
...     exit_velocity=1.0, exit_temperature=300.0, stack_diameter=1.0,
...     ambient_temperature=290.0, stability_class="G",
... )
Traceback (most recent call last):
...
ParameterError: stability_class must be one of A-F, got 'G'
References

Briggs, G. A. (1969). Plume Rise. USAEC TID-25075 (Eqs. 4.19b, 4.28, 4.33, 5.2). U.S. EPA, User's Guide for the Industrial Source Complex (ISC3) Dispersion Models, Vol. II, §1.1.4 (after Briggs 1971, 1975).

is_stable property

is_stable: bool

Whether the class is E or F (the stable formulas).

buoyancy_flux

buoyancy_flux() -> Float[Array, '']

F_b = g v_s d² (T_s − T_a)/(4 T_s) [m⁴ s⁻³], floored at 0 (no sinking).

Source code in src/plumax/gauss_plume/_src/plume_rise.py
def buoyancy_flux(self) -> Float[Array, ""]:
    """F_b = g v_s d² (T_s − T_a)/(4 T_s) [m⁴ s⁻³], floored at 0 (no sinking)."""
    # T_s − T_a
    excess = self.exit_temperature - self.ambient_temperature
    # g v_s d² (T_s − T_a) / (4 T_s)
    flux = (
        GRAVITY
        * self.exit_velocity
        * self.stack_diameter**2
        * excess
        / (4.0 * self.exit_temperature)
    )
    return jnp.maximum(flux, 0.0)

momentum_flux

momentum_flux() -> Float[Array, '']

F_m = v_s² d² T_a/(4 T_s) [m⁴ s⁻²].

Source code in src/plumax/gauss_plume/_src/plume_rise.py
def momentum_flux(self) -> Float[Array, ""]:
    """F_m = v_s² d² T_a/(4 T_s) [m⁴ s⁻²]."""
    # v_s² d² T_a / (4 T_s)
    return jnp.asarray(
        self.exit_velocity**2
        * self.stack_diameter**2
        * self.ambient_temperature
        / (4.0 * self.exit_temperature)
    )

stability_parameter

stability_parameter() -> Float[Array, '']

s = (g / T_a) ∂θ/∂z [s⁻²] of the stable classes; 0 for A–D.

Source code in src/plumax/gauss_plume/_src/plume_rise.py
def stability_parameter(self) -> Float[Array, ""]:
    """s = (g / T_a) ∂θ/∂z [s⁻²] of the stable classes; 0 for A–D."""
    gradient = STABLE_THETA_GRADIENT.get(self.stability_class, 0.0)
    # s = g ∂θ/∂z / T_a
    return jnp.asarray(GRAVITY * gradient / self.ambient_temperature)

briggs_plume_rise

briggs_plume_rise(x: Float[Array, '*obs'], *, exit_velocity: float | Float[Array, ''], exit_temperature: float | Float[Array, ''], stack_diameter: float | Float[Array, ''], ambient_temperature: float | Float[Array, ''], wind_speed: float | Float[Array, ''], stability_class: str = 'D') -> Float[Array, '*obs']

Briggs plume rise Δh(x) [m]; see :class:BriggsPlumeRise.

Parameters:

Name Type Description Default
x Float[Array, '*obs']

Downwind distance [m].

required
exit_velocity float | Float[Array, '']

Stack exit velocity v_s [m s⁻¹].

required
exit_temperature float | Float[Array, '']

Stack gas temperature T_s [K].

required
stack_diameter float | Float[Array, '']

Stack diameter d [m].

required
ambient_temperature float | Float[Array, '']

Ambient temperature T_a [K].

required
wind_speed float | Float[Array, '']

Wind speed u at the stack top [m s⁻¹].

required
stability_class str

Pasquill–Gifford class 'A' … 'F'.

'D'

Returns:

Type Description
Float[Array, '*obs']

Δh(x), with the final rise past x_f.

Examples:

The final rise of a buoyant plume in neutral air (F_b < 55):

>>> import jax.numpy as jnp
>>> rise = briggs_plume_rise(
...     jnp.array([1.0e5]), exit_velocity=10.0, exit_temperature=400.0,
...     stack_diameter=2.0, ambient_temperature=290.0, wind_speed=5.0,
... )
>>> flux = 9.80665 * 10.0 * 4.0 * 110.0 / 1600.0
>>> final = 1.6 * flux ** (1 / 3) * (49.0 * flux ** 0.625) ** (2 / 3) / 5.0
>>> bool(jnp.allclose(rise, final))
True
Source code in src/plumax/gauss_plume/_src/plume_rise.py
def briggs_plume_rise(
    x: Float[Array, "*obs"],
    *,
    exit_velocity: float | Float[Array, ""],
    exit_temperature: float | Float[Array, ""],
    stack_diameter: float | Float[Array, ""],
    ambient_temperature: float | Float[Array, ""],
    wind_speed: float | Float[Array, ""],
    stability_class: str = "D",
) -> Float[Array, "*obs"]:
    """Briggs plume rise Δh(x) [m]; see :class:`BriggsPlumeRise`.

    Args:
        x: Downwind distance [m].
        exit_velocity: Stack exit velocity v_s [m s⁻¹].
        exit_temperature: Stack gas temperature T_s [K].
        stack_diameter: Stack diameter d [m].
        ambient_temperature: Ambient temperature T_a [K].
        wind_speed: Wind speed u at the stack top [m s⁻¹].
        stability_class: Pasquill–Gifford class ``'A'`` … ``'F'``.

    Returns:
        Δh(x), with the final rise past x_f.

    Examples:
        The final rise of a buoyant plume in neutral air (F_b < 55):

        >>> import jax.numpy as jnp
        >>> rise = briggs_plume_rise(
        ...     jnp.array([1.0e5]), exit_velocity=10.0, exit_temperature=400.0,
        ...     stack_diameter=2.0, ambient_temperature=290.0, wind_speed=5.0,
        ... )
        >>> flux = 9.80665 * 10.0 * 4.0 * 110.0 / 1600.0
        >>> final = 1.6 * flux ** (1 / 3) * (49.0 * flux ** 0.625) ** (2 / 3) / 5.0
        >>> bool(jnp.allclose(rise, final))
        True
    """
    plume_rise = BriggsPlumeRise(
        exit_velocity=exit_velocity,
        exit_temperature=exit_temperature,
        stack_diameter=stack_diameter,
        ambient_temperature=ambient_temperature,
        stability_class=stability_class,
    )
    return plume_rise(x, wind_speed=wind_speed)

effective_height

effective_height(x: Float[Array, '*obs'], *, stack_height: float | Float[Array, ''], exit_velocity: float | Float[Array, ''], exit_temperature: float | Float[Array, ''], stack_diameter: float | Float[Array, ''], ambient_temperature: float | Float[Array, ''], wind_speed: float | Float[Array, ''], stability_class: str = 'D') -> Float[Array, '*obs']

Effective release height H_eff(x) = H_stack + Δh(x) [m].

Parameters:

Name Type Description Default
x Float[Array, '*obs']

Downwind distance [m].

required
stack_height float | Float[Array, '']

Physical stack height H_stack [m].

required
exit_velocity float | Float[Array, '']

Stack exit velocity v_s [m s⁻¹].

required
exit_temperature float | Float[Array, '']

Stack gas temperature T_s [K].

required
stack_diameter float | Float[Array, '']

Stack diameter d [m].

required
ambient_temperature float | Float[Array, '']

Ambient temperature T_a [K].

required
wind_speed float | Float[Array, '']

Wind speed u at the stack top [m s⁻¹].

required
stability_class str

Pasquill–Gifford class 'A' … 'F'.

'D'

Returns:

Type Description
Float[Array, '*obs']

H_eff at each x.

Examples:

At the stack itself the plume has not risen yet:

>>> import jax.numpy as jnp
>>> effective_height(
...     jnp.array([0.0]), stack_height=30.0, exit_velocity=10.0,
...     exit_temperature=400.0, stack_diameter=2.0,
...     ambient_temperature=290.0, wind_speed=5.0,
... ).tolist()
[30.0]
Source code in src/plumax/gauss_plume/_src/plume_rise.py
def effective_height(
    x: Float[Array, "*obs"],
    *,
    stack_height: float | Float[Array, ""],
    exit_velocity: float | Float[Array, ""],
    exit_temperature: float | Float[Array, ""],
    stack_diameter: float | Float[Array, ""],
    ambient_temperature: float | Float[Array, ""],
    wind_speed: float | Float[Array, ""],
    stability_class: str = "D",
) -> Float[Array, "*obs"]:
    """Effective release height H_eff(x) = H_stack + Δh(x) [m].

    Args:
        x: Downwind distance [m].
        stack_height: Physical stack height H_stack [m].
        exit_velocity: Stack exit velocity v_s [m s⁻¹].
        exit_temperature: Stack gas temperature T_s [K].
        stack_diameter: Stack diameter d [m].
        ambient_temperature: Ambient temperature T_a [K].
        wind_speed: Wind speed u at the stack top [m s⁻¹].
        stability_class: Pasquill–Gifford class ``'A'`` … ``'F'``.

    Returns:
        H_eff at each x.

    Examples:
        At the stack itself the plume has not risen yet:

        >>> import jax.numpy as jnp
        >>> effective_height(
        ...     jnp.array([0.0]), stack_height=30.0, exit_velocity=10.0,
        ...     exit_temperature=400.0, stack_diameter=2.0,
        ...     ambient_temperature=290.0, wind_speed=5.0,
        ... ).tolist()
        [30.0]
    """
    rise = briggs_plume_rise(
        x,
        exit_velocity=exit_velocity,
        exit_temperature=exit_temperature,
        stack_diameter=stack_diameter,
        ambient_temperature=ambient_temperature,
        wind_speed=wind_speed,
        stability_class=stability_class,
    )
    # H_eff = H_stack + Δh
    return stack_height + rise