Skip to content

Dispersion Modules

These modules handle the Gaussian plume and wind profile logic.

PKI Three-Dimensional Dispersion

The advanced photon point-kernel comparison evaluates physical plume values at paired three-dimensional points through WeatherAverager.average_dispersion_at_points. Coordinates are global east, north, and up distances relative to the chimney base. The returned dispersion has units s/m^3.

The observer height used by the runners defaults to the local terrain height. The weather-averaged callback masks points below terrain and points upwind of a weather bin. Photon rays that cross terrain are not blocked. PKI is opt-in and non-regulatory; the ENSI-G14 dispersion remains the reference calculation.

ensi_g14_calculator.dispersion

Modules

dispersion_factors_vogt

Classes
VogtModel

Dispersion parameters calculator (sigma_x and sigma_y), according to section A2.5.4 of the ENSI-G14

Usage:

    # instanciate:
    model = VogtModel()
    # pass quantities (with units!)
    from astropy.units import km, m
    x = 0.1 * km
    H = 75.0 * m
    # except the weather category, a character (A to F)
    w = "A"
    # recover whatever you need, see below:
    print("Params:", model.vogt_params(w, H))
    print("sigma_y:", model.sigma_y(x, w, H))
    print("sigma_z:", model.sigma_z(x, w, H))

Functions
vogt_params(weather, H_eff)

calculates p_y, q_y, p_z, q_z according to section A2.5.4 of the ENSI G14 (interpolates between tabulated values).

Parameters:

Name Type Description Default
weather

string, weather category ('A', 'B', ..., 'F')

required
H_eff

effective release height, with astropy units (length)

required

Returns:

Type Description

VogtParams instance, where the p_y, q_y, p_z and q_z can be acessed by doing i.e. instance.p_y

sigma_y(x_m, weather, H_eff)

Horizontal dispersion (perpendicular to wind axis) parameter, standard deviation of the gaussian plume.

Parameters:

Name Type Description Default
x_m

distance along the plume axis, with astropy units (length)

required
weather

string, weather category ('A', 'B', ..., 'F')

required
H_eff

effective release height, with astropy units (length)

required

Returns:

Type Description

sigma_y, quantity with astropy units, m

sigma_z(x_m, weather, H_eff)

Vertical dispersion (perpendicular to wind axis) parameter, standard deviation of the gaussian plume.

Parameters:

Name Type Description Default
x_m

distance along the plume axis, with astropy units (length)

required
weather

string, weather category ('A', 'B', ..., 'F')

required
H_eff

effective release height, with astropy units (length)

required

Returns:

Type Description

sigma_z, quantity with astropy units, m

gaussian_plume

Classes
SubmersionCorrectionModel

Calculates the correction coefficients \(KF_{sub,shape}\) and \(KF_{sub,axis}\), used in A2.1.1.2.

Usage:

    corr = SubmersionCorrectionModel()
    print(corr.kf_sub_shape(10*m, 5*m))
    print(corr.kf_sub_axis(10*m, 5*m, H_eff_oro=20*m, y=0*m))
potential deviations: set ENFORCE_MIN_SIGMA = False to deviate from G-14 behaviour for short distances.
So instanciate class, then override it. (default True: applies rule 4 page 13 Beilage)

Functions
p_shape(sigma_y, sigma_z)

P_shape polynomial of section A2.1.1.2, ENSI G14. sigma_y and sigma_z are to be provided with units, but they will be cast to m in the formula.

Parameters:

Name Type Description Default
sigma_y

float or array, horizontal dispersion parameter, with astropy units (length)

required
sigma_z

float or array, vertical dispersion parameter, with astropy units (length)

required

Returns:

Type Description

unitless, float or array.

kf_sub_shape(sigma_y, sigma_z)

\(KF_{sub,shape}\) term of section A2.1.1.2, ENSI G14. sigma_y and sigma_z are to be provided with units, but they will be cast to m in the formula.

Parameters:

Name Type Description Default
sigma_y

float or array, horizontal dispersion parameter, with astropy units (length)

required
sigma_z

float or array, vertical dispersion parameter, with astropy units (length)

required

Returns:

Type Description

unitless, float or array.

p_axis_from_vars(mu_r_asym, r_over_sy_p, r_over_sz_p)

\(P_{axis}\) polynomial of page 24 of the ENSI G14 2025 (section A2.1.1.2). Since the arguments are "pre-processed", you should not be using this function unless you are working on the internals of this package.

Parameters:

Name Type Description Default
mu_r_asym

first argument, mu * r * asym (see _asym method of this class; r defined on page 24)

required
r_over_sy_p

second argument of the formula

required
r_over_sz_p

third argument of the formula

required

Returns:

Type Description
kf_sub_axis(sigma_y, sigma_z, H_eff_oro, y, mu=None)

\(KF_{sub, axis}\) term of bottom of page 23, ENSI G14 2025.

Parameters:

Name Type Description Default
sigma_y

float or array, horizontal dispersion parameter, with astropy units (length)

required
sigma_z

float or array, vertical dispersion parameter, with astropy units (length)

required
H_eff_oro

float or array, effective height, orography corrected (see A2.5.2 and release_height file), units length.

required
y

float or array, distance to plume axis (perpendicular to wind direction)

required
mu

air attenuation coefficient, given in ENSI G14 params but see discussion on page 24.

None

Returns:

Type Description

KF_{sub,axis} coefficient, unitless.

GaussianPlumeModel

Class calculating the dispersion factors \(chi_K\) and \(chi_{K,S}\), the fundamental quantites upon which everything else is computed.

Functions
chi_k(sigma_y, sigma_z, U_Ha, H_eff_oro, y, G_t, sigma_y0, sigma_z0, U0, height=None, weight_elevated=1.0, weight_ground=1.0, height_ground=None)

Computes the dispersion factor \(chi_K\), base quantity upon which deposition and dose calculation rely.

When height is provided, it is the observer height above local terrain (not global chimney-relative z) and direct plus reflected-image vertical Gaussian terms are used. A one-dimensional height array is interpreted as trailing vertical levels when another non-scalar plume input has a different shape; otherwise it is broadcast elementwise. N-dimensional height arrays are evaluated as paired points and broadcast using normal numpy rules.

By the way, when I added height, I realised we need to make an assumption on the type of plume ENSI was envisioning. Since the ENSI plume is evaluated at 0, we do not see whether they meant to add a second plume reflecting on the ground, as is usual. From the normalisation of the plume (1/pi and not 1/2pi), I think they meant to add a reflected plume. Thus this is what I implemented here. For the normal G-14 use, the plume is still evaluated on the ground, and adding the reflected term makes no difference. It only impacts PKI, where we need to evaluate the plume in its bulk and not only on th eground.

Parameters:

Name Type Description Default
sigma_y

float or array, horizontal dispersion parameter, with astropy units (length)

required
sigma_z

float or array, vertical dispersion parameter, with astropy units (length)

required
U_Ha

velocity of wind at height of release, with astropy units (length/time)

required
H_eff_oro

float or array, effective height, orography corrected (see A2.5.2 and release_height file), units length.

required
y

float or array, distance to plume axis (perpendicular to wind direction)

required
G_t

ground fraction

required
sigma_y0

same as sigma_y but evaluated at ground level rather than at plume height level.

required
sigma_z0

same as sigma_z but evaluated at ground level rather than at plume height level.

required
U0

same as U_Ha, but wind speed at ground level.

required
height

optional observer height above local terrain, with astropy length units.

None
weight_elevated

optional dimensionless factor (scalar or array) multiplying the elevated component, e.g. radioactive decay during transport (see plume_decay.py).

1.0
weight_ground

same for the ground-level component.

1.0
height_ground

optional observer height used for the ground-level component only, same shape as height; defaults to height. Used by the near-field stretched-string option, where the vertical offset is already in the travel distance.

None

Returns:

Type Description

float or array, with astropy units (s/m^3), dispersion factor.

chi_k_s(sigma_y, sigma_z, U_Ha, H_eff_oro, y, G_t, sigma_y0, sigma_z0, U0, mu=None, weight_elevated=1.0, weight_ground=1.0, height=None)

Computes the pseudo-dispersion factor \(chi_{K,S}\), to be used for submersion dose calculation. (not a real dispersion) HERE MAKE SURE TO COMPUTE THE SIGMAs FOR x=5km if your x>5km (page 15 of annex document to G14) I cannot verify you did it correctly internally to this function. However, you should not be calling this function yourself, there are higher level routines in the package that should do it for you.

Parameters:

Name Type Description Default
sigma_y

dispersion coefficient, as computed by the VogtModel class in dispersion_factors_vogt.py

required
sigma_z

ditto but vertical

required
U_Ha

Wind speed in m/s at the uncorrected release height (e.g. stack height)

required
H_eff_oro

Orography-corrected, effective plume height in m above the point in the surroundings with absolute coordinates X (eastward) and Y (northward) relative to the release location (cf. Sec. A2.5.2). Without orography correction, set Heff,oro = Heff .

required
y

lateral deviation from the plume axis, orthogonal to the direction of dispersion

required
G_t

Fraction of the release that, due to building influences, is to be treated as a ground-level release (cf. Sec. A2.5.1). computed by EffectiveReleaseModel.ground_fraction

required
sigma_y0

Gaussian dispersion parameter for ground-level release.

required
sigma_z0

Gaussian dispersion parameter for ground-level release.

required
U0

Wind speed in m/s near the ground (10 m above ground).

required
mu

attenuation coefficient in air, should be read from the package data.

None
height

optional observer height above local terrain, with astropy length units. Outside G-14: the vertical offset between observer and plume axis, |H_eff_oro - height| (and height for the ground-level component), replaces H_eff_oro in KF_sub,axis.

None
weight_elevated

optional dimensionless factor (scalar or array) multiplying the elevated component, e.g. radioactive decay during transport (see plume_decay.py).

1.0
weight_ground

same for the ground-level component.

1.0

Returns:

Type Description

chi_ks, float or array, in s/m^3.

plume_decay

Classes
DecayedDispersion dataclass

Dispersion of one emitted nuclide with decay during transport already applied.

parent: chi weighted by the parent survival g_m(t), with units (s/m^3) daughters: {daughter nuclide: chi weighted by the in-growth g_d(t)}, activity of the daughter per emitted parent Bq (branching ratios are applied in the dose functions, as in G-14)

Functions
__getitem__(index)

Select points, e.g. one receptor of an array: decayed[i].

Functions
parent_survival(lambda_m)

Time weight g_m(t) = exp(-lambda_m t).

Parameters:

Name Type Description Default
lambda_m

decay constant of the parent, with units (1/time)

required

Returns:

Type Description

callable t (Quantity, time) -> dimensionless array

daughter_ingrowth(lambda_m, lambda_d)

Time weight g_d(t) = lambda_d / (lambda_d - lambda_m) (exp(-lambda_m t) - exp(-lambda_d t)): activity of the daughter at time t per unit initial activity of the parent.

Parameters:

Name Type Description Default
lambda_m

decay constant of the parent, with units (1/time)

required
lambda_d

decay constant of the daughter, with units (1/time)

required

Returns:

Type Description

callable t (Quantity, time) -> dimensionless array

decayed_dispersion(evaluate, nuclide, dose_calculator)

Evaluate the decayed dispersion of nuclide and of all its daughters (G-14 Table 4.3.1).

    decayed = decayed_dispersion(
        lambda w: averager.average_dispersion_at_points(x, y, z, weather, time_weight=w),
        "F-18", LongTermDoseCalculator(),
    )
    dose = LongTermDoseCalculator().inhalation("F-18", Q, decayed)   # no T_fz

Parameters:

Name Type Description Default
evaluate Callable

callable time_weight -> chi (Quantity), e.g. a WeatherAverager method with time_weight. It may also return a tuple of Quantities, e.g. (chi_K, chi_K,S) of average_dispersion.

required
nuclide str

string, e.g. 'F-18'

required
dose_calculator

a dose calculator (short or long term), used for the decay constants and daughters

required

Returns:

Type Description
DecayedDispersion

DecayedDispersion, or a tuple of them if evaluate returns a tuple

parent_dispersion(chi)

The parent's dispersion: chi.parent for a DecayedDispersion, chi itself otherwise (G-14 path).

release_height

Classes
EffectiveReleaseModel

usage:

    model = EffectiveReleaseModel()

    from astropy.units import m, s
    H_a = 60.0 * m
    D_i = 2.0 * m
    D_e = 2.2 * m
    W_0 = 15.0 * m / s
    U_Ha = 6.0 * m / s
    S = 0.02 / (s**2)   # only needed for E/F

    w = "D"
    dH = model.plume_rise(w, D_i, D_e, W_0, U_Ha, S=S)
    print("delta H:", dH)
    print("H_eff:", model.effective_release_height(H_a, w, D_i, D_e, W_0, U_Ha, S=S))

    H_G = 20.0 * m
    print("G_t:", model.ground_fraction(w, H_a, H_G, W_0, U_Ha, scenario="normal"))

Functions
downwash_correction(D_e, W_0, U_Ha)

C symbol on page 33, section A2.5.1

Parameters:

Name Type Description Default
D_e

astropy quantity (units length), external diameter of chimney

required
W_0

astropy quantity (units length/time), exhaust velocity of the chimney

required
U_Ha

astropy quantity (units length/time), wind speed at the height of the chimney

required

Returns:

Type Description

downwash correction

plume_rise(weather, D_i, D_e, W_0, U_Ha, S=None, x=None)

Delta H according to section 2.5.1

Parameters:

Name Type Description Default
weather

string, weather category (from 'A' to 'F')

required
D_i

internal diameter of chimney, with units (length)

required
D_e

external diameter of chimney, with units (length)

required
W_0

exhaust speed of chimney, with units (length/time)

required
U_Ha

astropy quantity (units length/time), wind speed at the height of the chimney

required
S

stability parameter, should be read from the package data, keep it to the default (None).

None
x

optional downwind distance(s) at which the momentum rise dH1 is evaluated, with units (length). Defaults to the G-14 value of 200 m (final rise). Only the near-field module passes it.

None

Returns:

Type Description

plume rise with units (length)

effective_release_height(H_a, weather, D_i, D_e, W_0, U_Ha, scenario='normal', x=None)

H_eff according to section 2.5.1

Parameters:

Name Type Description Default
weather

string, weather category (from 'A' to 'F')

required
D_i

internal diameter of chimney, with units (length)

required
D_e

external diameter of chimney, with units (length)

required
W_0

exhaust speed of chimney, with units (length/time)

required
U_Ha

astropy quantity (units length/time), wind speed at the height of the chimney

required
scenario

string, 'normal' or accident'. If accident, the release height is that of the chimney, no rise.

'normal'
x

optional downwind distance(s) for the momentum rise, see plume_rise. Defaults to 200 m.

None

Returns:

Type Description

effective release height with units (length)

ground_fraction(weather, H_a, H_G, W_0, U_Ha, scenario='normal')

Ground fraction G_t according to section 2.5.1, bottom of page 23 and top of page 24.

Parameters:

Name Type Description Default
weather

string, weather category (from 'A' to 'F')

required
H_a

height of chimney (total stack height), with units (length)

required
H_G

height of nearby buildings, with units (length)

required
W_0

exhaust speed of chimney, with units (length/time)

required
U_Ha

astropy quantity (units length/time), wind speed at the height of the chimney.

required
scenario

string, 'normal' or 'accident'. If accident, the release height is that of the chimney, no rise.

'normal'

Returns:

Type Description

effective release height with units (length)

heff_oro_axis(H_eff, weather, h_oro_x0)

orography correction for receptor points directly beneath plume axis, first step to computing the actual H_eff_oro.

Parameters:

Name Type Description Default
H_eff

effective release height, with units (length)

required
weather

string, weather category (from 'A' to 'F')

required
h_oro_x0

terrain elevation (relative to the base of the stack, which is at 0) at distance x from the stack, on the plume axis.

required

Returns:

Type Description

heff_oro_axis, with units (height)

heff_oro(H_eff, weather, h_oro_x0, h_oro_xy)

Computes the effective height of the release, plus the terrain height differential.

Parameters:

Name Type Description Default
H_eff

effective release height, with astropy units (length)

required
weather

string, weather category (from 'A' to 'F')

required
h_oro_x0

terrain elevation (relative to the base of the stack, which is at 0) at distance x from the stack, on the plume axis.

required
h_oro_xy

terrain elevation (relative to the base of the stack, which is at 0) at distance x from the stack down the plume axis, and distance y from the plume axis (perpendicular)

required

Returns:

Type Description

effective release height, orography corrected (with units, height)

wind_profile

Classes
WindProfileModel

Class computing wind speed correction depending on height. Usage:

    model = WindProfileModel()
    from astropy.units import m, s
    U_M = 5.0 * m / s
    z_m = 10.0 * m
    H_a = 60.0 * m
    w = "D"
    print("U(H_a):", model.wind_at_release(U_M, H_a, z_m, w))

Functions
wind_at_release(U_M, H_a, z_m, weather)

Estimates U_Ha (wind speed at height H_a) starting from the wind speed U_M measured at height z_m

Parameters:

Name Type Description Default
U_M

measured wind speed, with units (length/time)

required
H_a

desired height, with units (height)

required
z_m

measurement height, normally 10m, with units (height)

required
weather

string, weather category (from 'A' to 'F').

required

Returns:

Type Description

wind speed estimate at height H_a, with units (length/time).