Gaussian Dispersion¶
Toolkit name: GaussianDispersion | Constant: toolkitHome.GAUSSIANDISPERSION
The Gaussian dispersion toolkit computes the concentration and dosage of a gas cloud released from a single source, using Gaussian puff equations with Briggs (rural) dispersion coefficients. It distinguishes instantaneous releases (a mass, e.g. 1 kg) from continuous releases (a rate, e.g. 1 g/s — currently broken, see below), and handles ground reflections, and an optional depletion factor for dry deposition. Results are xarray.DataArray objects on a regular (time, x, y, z) grid, with the wind blowing along the x axis from a source at x = 0, y = 0.
The toolkit does not store anything in the database: it is a set of calculation helpers (meteorology, sigmas, gas cloud) plus a plotting layer.
from hera import toolkitHome
gauss = toolkitHome.getToolkit(toolkitHome.GAUSSIANDISPERSION, projectName="MY_PROJECT")
All dimensional inputs are pint quantities (hera.utils.ureg); plain numbers are interpreted in the default units noted below.
Workflow¶
A calculation has four steps:
- Meteorology — wind speed at a reference height, stability class, roughness.
- Space-time grid — the extents and resolution of the output grid.
- Gas cloud — the source (amount, height, initial size) bound to the meteorology and the grid.
- Concentration / dosage — computed from the gas cloud.
1. Meteorology¶
from hera.utils import ureg
# Wind speed given at 10 m
met = gauss.getMeteorologyFromU10(
u10=2 * ureg.m / ureg.s,
inversion=300 * ureg.m, # inversion (mixing) height
verticalProfileType="powerLaw", # "powerLaw" (default), "log" or "uniformWind"
stability="D", # Pasquill class A-F
z0=0.1 * ureg.m, # roughness length
temperature=ureg.Quantity(20, ureg.degC),
)
# Wind speed given at another reference height
met = gauss.getMeteorologyFromURefHeight(u=3 * ureg.m / ureg.s, refHeight=20 * ureg.m,
inversion=300 * ureg.m, stability="D")
met.getWindVelocity(height=10 * ureg.m) # wind speed at a height (profile clipped to 0-300 m)
The remaining keyword arguments are ustar (default 0.3 m/s) and skinSurfaceTemperature (default 35 °C).
2. Space-time grid¶
getSpaceTime builds the grid dictionary used by the gas cloud. It chooses the horizontal cell size as a multiple of the distance the cloud travels in one time step (dxdy = dt · u · dxdy_multiplier), and a time span long enough for the cloud to pass maxx:
initialCloudSize = [1 * ureg.m, 1 * ureg.m, 1 * ureg.m] # sigma_x, sigma_y, sigma_z at the source
spaceTime = gauss.getSpaceTime(
meteorology=met,
sourceHeight=10 * ureg.m,
wind_profile_type="default", # "default" (the meteorology profile) or "HotSpot"
maxx=1000 * ureg.m,
maxz=50 * ureg.m,
dt=10 * ureg.s,
dz=1 * ureg.m,
dxdy_multiplier=1,
minimal_maxy=200 * ureg.m, # the y extent is rounded up to a multiple of dxdy
initialCloudSize=initialCloudSize,
)
# {'minx', 'maxx', 'miny', 'maxy', 'minz', 'maxz', 'dxdy', 'dz', 'timeSpan', 'dt'}
You can also build the dictionary yourself with the same keys (all pint quantities).
3. Gas cloud¶
cloud = gauss.getGasCloud(
sourceQ=1 * ureg.kg, # [mass] -> instantaneous, [mass/time] -> continuous
sourceHeight=10 * ureg.m,
initialCloudSize=initialCloudSize,
meteorology=met,
wind_profile_type="default",
spaceTime=spaceTime,
deposition_velocity=0 * ureg.m / ureg.s, # used only when DF=True
sigmaTypeName="briggsRural", # see gauss.listSigmaTypes()
)
getGasCloud returns an instantaneousReleaseGasCloud or a continuousReleaseGasCloud (from hera.simulations.gaussian.gasCloud), depending on the units of sourceQ. A ValueError is raised if sourceQ is neither a mass nor a mass rate.
4. Concentration and dosage¶
Instantaneous release:
C = cloud.getConcentration_inst(numOfReflections=3) # mg/m³, dims (time, x, y, z)
D = cloud.getDosage_inst(numOfReflections=3) # mg·min/m³ (time-integrated, erf form)
D2 = cloud.getDosage_inst_NoERF() # dosage by numerical integration of C
# Normalised (per unit mass) versions
C1 = cloud.getConcentration_inst_noQ() # 1/m³
Continuous release:
cloud = gauss.getGasCloud(sourceQ=1 * ureg.g / ureg.s, ...)
C = cloud.getConcentration_cont() # concentration of a constant-rate release
D = cloud.getDosage_cont_NoERF()
Known issue
In master every continuousReleaseGasCloud method (getConcentration_cont, getConcentration_cont_NoERF, getDosage_cont_NoERF, getDosage_cont_doubleNoERF) raises AttributeError: they call the getDosage_inst_*_noQ methods, which are defined on instantaneousReleaseGasCloud, not on the common base class (hera/simulations/gaussian/gasCloud.py:596). Only instantaneous releases work.
The time coordinate is in minutes from the release; x, y, z are in metres. The units are stored in C.attrs['Q']. Pass DF=True to the dosage functions to apply the dry-deposition depletion factor computed from deposition_velocity.
For radiological releases the instantaneous cloud also provides time-integrated activity concentrations (getTIAC_inst(specifitActivity, ...), getTIAC_inst_NoERF(...) and their _noQ variants, output in Bq·s/m³).
Sigmas¶
gauss.listSigmaTypes() # ['briggsRural']
sigma = gauss.getSigmaType("briggsRural")
sigma.getSigma(x=[100, 500, 1000], stability="D", sigma0=initialCloudSize)
# {'sigmaX': ..., 'sigmaY': ..., 'sigmaZ': ..., 'distance': ...}
Presentation¶
gauss.presentation plots the results with matplotlib (each call shows the figure):
| Method | Plot |
|---|---|
plotMaxConcentrationOverTime(C, y, z, x_min=None, x_max=None) |
Maximum concentration along x at (y, z) |
plotFixedPointConcentrationOverTime(C, x, y, z, t_min=None, t_max=None) |
Concentration time series at a point |
plotDosagePerDistance(D, y, z, time) |
Dosage along x at a given time |
plotFixedPointDosageOverTime(D, x, y, z) |
Dosage time series at a point |
The _noQ variants (plotMaxConcentrationOverTime_noQ, plotFixedPointConcentrationOverTime_noQ, plotTIACPerDistance_noQ, plotFixedPointTIACOverTime_noQ) plot the normalised results.
Complete example¶
from hera import toolkitHome
from hera.utils import ureg
gauss = toolkitHome.getToolkit(toolkitHome.GAUSSIANDISPERSION, projectName="MY_PROJECT")
met = gauss.getMeteorologyFromU10(u10=3 * ureg.m / ureg.s, inversion=500 * ureg.m, stability="D")
sigma0 = [1 * ureg.m, 1 * ureg.m, 1 * ureg.m]
spaceTime = gauss.getSpaceTime(meteorology=met, sourceHeight=2 * ureg.m, wind_profile_type="default",
maxx=2000 * ureg.m, maxz=30 * ureg.m, dt=10 * ureg.s, dz=1 * ureg.m,
dxdy_multiplier=1, minimal_maxy=300 * ureg.m, initialCloudSize=sigma0)
cloud = gauss.getGasCloud(sourceQ=10 * ureg.kg, sourceHeight=2 * ureg.m, initialCloudSize=sigma0,
meteorology=met, wind_profile_type="default", spaceTime=spaceTime,
deposition_velocity=0 * ureg.m / ureg.s)
C = cloud.getConcentration_inst()
D = cloud.getDosage_inst()
gauss.presentation.plotMaxConcentrationOverTime(C, y=0 * ureg.m, z=1.5 * ureg.m)
gauss.presentation.plotDosagePerDistance(D, y=0 * ureg.m, z=1.5 * ureg.m, time=D.time[-1].item() * ureg.min)
There is no CLI for this toolkit.
For implementation details, see the Developer Guide. For the full API, see the API Reference.