slabx 1.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- slabx-1.0.3/LICENSE +25 -0
- slabx-1.0.3/PKG-INFO +200 -0
- slabx-1.0.3/README.md +163 -0
- slabx-1.0.3/pyproject.toml +68 -0
- slabx-1.0.3/setup.cfg +4 -0
- slabx-1.0.3/src/slabx/__init__.py +0 -0
- slabx-1.0.3/src/slabx/coefficients.py +445 -0
- slabx-1.0.3/src/slabx/core/__init__.py +0 -0
- slabx-1.0.3/src/slabx/core/height_closure.py +237 -0
- slabx-1.0.3/src/slabx/core/plume.py +1286 -0
- slabx-1.0.3/src/slabx/core/puff.py +459 -0
- slabx-1.0.3/src/slabx/core/source.py +617 -0
- slabx-1.0.3/src/slabx/core/trajectory.py +450 -0
- slabx-1.0.3/src/slabx/core/vertical_jet.py +326 -0
- slabx-1.0.3/src/slabx/io/__init__.py +0 -0
- slabx-1.0.3/src/slabx/post/__init__.py +0 -0
- slabx-1.0.3/src/slabx/post/concentration.py +395 -0
- slabx-1.0.3/src/slabx/scope.py +145 -0
- slabx-1.0.3/src/slabx/submodels/__init__.py +0 -0
- slabx-1.0.3/src/slabx/submodels/added_mass.py +78 -0
- slabx-1.0.3/src/slabx/submodels/atmosphere.py +389 -0
- slabx-1.0.3/src/slabx/submodels/entrainment.py +520 -0
- slabx-1.0.3/src/slabx/submodels/ground.py +112 -0
- slabx-1.0.3/src/slabx/submodels/rainout.py +230 -0
- slabx-1.0.3/src/slabx/thermo/__init__.py +0 -0
- slabx-1.0.3/src/slabx/thermo/base.py +340 -0
- slabx-1.0.3/src/slabx/thermo/coolprop.py +581 -0
- slabx-1.0.3/src/slabx/thermo/equilibrium.py +334 -0
- slabx-1.0.3/src/slabx/thermo/mixture.py +176 -0
- slabx-1.0.3/src/slabx/validation/__init__.py +0 -0
- slabx-1.0.3/src/slabx/validation/_data_access.py +106 -0
- slabx-1.0.3/src/slabx/validation/data/provenance/README.md +146 -0
- slabx-1.0.3/src/slabx/validation/data/provenance/publication_status.csv +28 -0
- slabx-1.0.3/src/slabx/validation/data/provenance/source_manifest.csv +11 -0
- slabx-1.0.3/src/slabx/validation/data/provenance/variable_mapping.csv +28 -0
- slabx-1.0.3/src/slabx/validation/data/smedis_inventory.csv +29 -0
- slabx-1.0.3/src/slabx/validation/field_trials.py +469 -0
- slabx-1.0.3/src/slabx/validation/lng_pools.py +194 -0
- slabx-1.0.3/src/slabx/validation/metrics.py +345 -0
- slabx-1.0.3/src/slabx/validation/smedis.py +302 -0
- slabx-1.0.3/src/slabx/validation/thorney_island.py +186 -0
- slabx-1.0.3/src/slabx/validation/wind_tunnel.py +153 -0
- slabx-1.0.3/src/slabx.egg-info/PKG-INFO +200 -0
- slabx-1.0.3/src/slabx.egg-info/SOURCES.txt +78 -0
- slabx-1.0.3/src/slabx.egg-info/dependency_links.txt +1 -0
- slabx-1.0.3/src/slabx.egg-info/requires.txt +13 -0
- slabx-1.0.3/src/slabx.egg-info/top_level.txt +1 -0
- slabx-1.0.3/tests/test_added_mass.py +195 -0
- slabx-1.0.3/tests/test_atmosphere.py +264 -0
- slabx-1.0.3/tests/test_composition.py +156 -0
- slabx-1.0.3/tests/test_concentration.py +221 -0
- slabx-1.0.3/tests/test_convergence.py +211 -0
- slabx-1.0.3/tests/test_coolprop.py +235 -0
- slabx-1.0.3/tests/test_desert_tortoise.py +304 -0
- slabx-1.0.3/tests/test_eec.py +173 -0
- slabx-1.0.3/tests/test_entrainment.py +634 -0
- slabx-1.0.3/tests/test_field_trials.py +345 -0
- slabx-1.0.3/tests/test_fladis.py +211 -0
- slabx-1.0.3/tests/test_fortran_oracle.py +194 -0
- slabx-1.0.3/tests/test_fuzz_fortran.py +217 -0
- slabx-1.0.3/tests/test_ground.py +124 -0
- slabx-1.0.3/tests/test_height_closure.py +186 -0
- slabx-1.0.3/tests/test_lathen.py +176 -0
- slabx-1.0.3/tests/test_lng_pools.py +200 -0
- slabx-1.0.3/tests/test_meander.py +135 -0
- slabx-1.0.3/tests/test_metrics.py +228 -0
- slabx-1.0.3/tests/test_plume.py +309 -0
- slabx-1.0.3/tests/test_prairie_grass.py +180 -0
- slabx-1.0.3/tests/test_puff.py +324 -0
- slabx-1.0.3/tests/test_rainout.py +361 -0
- slabx-1.0.3/tests/test_scope.py +194 -0
- slabx-1.0.3/tests/test_smedis.py +178 -0
- slabx-1.0.3/tests/test_source.py +277 -0
- slabx-1.0.3/tests/test_source_types.py +261 -0
- slabx-1.0.3/tests/test_thermo.py +454 -0
- slabx-1.0.3/tests/test_thorney_dose.py +187 -0
- slabx-1.0.3/tests/test_thorney_island.py +177 -0
- slabx-1.0.3/tests/test_trajectory.py +282 -0
- slabx-1.0.3/tests/test_vertical_jet.py +335 -0
- slabx-1.0.3/tests/test_wind_tunnel.py +163 -0
slabx-1.0.3/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ugwiyeon Lee
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Third-party material, including the original SLAB source and its terms, is
|
|
25
|
+
described in THIRD_PARTY_NOTICES.md. None of it is included here.
|
slabx-1.0.3/PKG-INFO
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: slabx
|
|
3
|
+
Version: 1.0.3
|
|
4
|
+
Summary: A Python reimplementation of the SLAB dense-gas dispersion model, verified against the original and evaluated against field and wind-tunnel trials
|
|
5
|
+
Author-email: Ugwiyeon Lee <lyullee@kgs.or.kr>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/lyullee/slabx
|
|
8
|
+
Project-URL: Repository, https://github.com/lyullee/slabx
|
|
9
|
+
Project-URL: Documentation, https://github.com/lyullee/slabx#readme
|
|
10
|
+
Project-URL: Issues, https://github.com/lyullee/slabx/issues
|
|
11
|
+
Project-URL: Archived version, https://doi.org/10.5281/zenodo.22023625
|
|
12
|
+
Keywords: dense gas dispersion,atmospheric dispersion,model validation,SLAB,process safety
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: numpy>=1.24
|
|
27
|
+
Requires-Dist: scipy>=1.10
|
|
28
|
+
Provides-Extra: thermo
|
|
29
|
+
Requires-Dist: CoolProp>=6.5; extra == "thermo"
|
|
30
|
+
Provides-Extra: data
|
|
31
|
+
Requires-Dist: pandas>=2.0; extra == "data"
|
|
32
|
+
Requires-Dist: xarray>=2023.1; extra == "data"
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# slabx
|
|
39
|
+
|
|
40
|
+
[](https://doi.org/10.5281/zenodo.22023625)
|
|
41
|
+
[](LICENSE)
|
|
42
|
+
|
|
43
|
+
A Python reimplementation of **SLAB**, the dense-gas dispersion model of
|
|
44
|
+
Ermak (1990, UCRL-MA-105607), verified against the original Fortran and
|
|
45
|
+
evaluated against 38 field and wind-tunnel trials.
|
|
46
|
+
|
|
47
|
+
The implementation follows the published model formulation and the user's
|
|
48
|
+
manual, in a program structure of its own; individual results were then
|
|
49
|
+
compared against the original Fortran, which was also consulted for
|
|
50
|
+
implementation details the manual leaves open. It is therefore not a
|
|
51
|
+
clean-room implementation, and the comparison points are recorded in the
|
|
52
|
+
source as line references so that the checking is visible.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from slabx.core.plume import run_dispersion
|
|
56
|
+
from slabx.core.source import EvaporatingPool
|
|
57
|
+
from slabx.post.concentration import concentration_field
|
|
58
|
+
from slabx.submodels.atmosphere import Atmosphere
|
|
59
|
+
from slabx.thermo.base import LegacyThermo, Substance, water_backend
|
|
60
|
+
|
|
61
|
+
LNG = Substance(name="LNG", mw=0.016043, cp_vapour=2238.0, cp_liquid=3348.5,
|
|
62
|
+
dh_vap=509900.0, T_boil=111.7, rho_liquid=424.1)
|
|
63
|
+
|
|
64
|
+
atm = Atmosphere(u_ref=1.94, z_ref=3.0, T=290.0, rh=50.0, z0=2e-4,
|
|
65
|
+
stability="E")
|
|
66
|
+
|
|
67
|
+
# The pool area is the spill divided by the evaporation flux, not the
|
|
68
|
+
# footprint quoted in the manual, and the manual's worked example uses
|
|
69
|
+
# demonstration weather rather than the trial's. Both matter: the manual's
|
|
70
|
+
# 657 m2 with T = 306 K and 4.6 % humidity gives 386 m instead of 449.
|
|
71
|
+
src = EvaporatingPool(substance=LNG, rate=116.93, area=116.93 / 0.167,
|
|
72
|
+
duration=107.0)
|
|
73
|
+
|
|
74
|
+
traj, used = run_dispersion(src, atm, LegacyThermo(LNG), water_backend(),
|
|
75
|
+
x_max=2000.0, n_puff_steps=40)
|
|
76
|
+
field = concentration_field(traj, atm, z=1.0, t_avg=80.0, t_release=107.0)
|
|
77
|
+
|
|
78
|
+
print(f"{field.distance_to(0.05):.0f} m to LFL") # 449; measured 455
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`slabx.validation.lng_pools` sets all of this from the trial record, which
|
|
82
|
+
is the path the paper's numbers come from -- but it needs the observations,
|
|
83
|
+
which are not distributed here. See below.
|
|
84
|
+
|
|
85
|
+
## Install
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install -e . # numpy, scipy
|
|
89
|
+
pip install CoolProp # optional: real-fluid properties
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Python 3.10+. `QUICKSTART.md` has a runnable scenario template and a
|
|
93
|
+
troubleshooting table.
|
|
94
|
+
|
|
95
|
+
## What it does
|
|
96
|
+
|
|
97
|
+
Four source types — evaporating pool, horizontal jet, vertical jet with plume
|
|
98
|
+
rise, instantaneous release — integrated as a shallow-layer model with the
|
|
99
|
+
plume-to-puff transition of the original.
|
|
100
|
+
|
|
101
|
+
Beyond the original, all off by default so the reproduction is never disturbed:
|
|
102
|
+
|
|
103
|
+
| | |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `rainout=True` | droplet break-up, settling and removal |
|
|
106
|
+
| `kinetic_evaporation=True` | finite-rate droplet evaporation |
|
|
107
|
+
| `added_mass=True` | oblate-spheroid added mass on buoyant rise |
|
|
108
|
+
| `substrate=DRY_SOIL` | ground heat transfer |
|
|
109
|
+
| `CoolPropThermo` | real-fluid properties, and multicomponent mixtures |
|
|
110
|
+
| `meander_closure="sigma_theta"` | meander from measured wind-direction variability |
|
|
111
|
+
|
|
112
|
+
Thirty-eight coefficients are exposed as a frozen dataclass with presets, so
|
|
113
|
+
sensitivity studies do not need edits to the source.
|
|
114
|
+
|
|
115
|
+
## How far it has been checked
|
|
116
|
+
|
|
117
|
+
**Against the original Fortran.** The five decks of the manual agree to
|
|
118
|
+
0.05–1.48 % on every cloud variable, at the level of the original's own
|
|
119
|
+
discretisation error. A random differential test over 108 decks — four source
|
|
120
|
+
types, five materials, the full stability range — puts the median difference
|
|
121
|
+
at 0.09 % on temperature and 0.67 % on concentration.
|
|
122
|
+
|
|
123
|
+
The comparison is against Ermak's Fortran itself, compiled from source. Early
|
|
124
|
+
work used a JavaScript transcription and misattributed five of six differences
|
|
125
|
+
to SLAB as a result; `docs/02_VALIDATION_REFERENCE.md` §2.5 records what that
|
|
126
|
+
cost and how it was found.
|
|
127
|
+
|
|
128
|
+
**Against measurements.** Ten LNG pool trials (Burro, Coyote, Maplin Sands),
|
|
129
|
+
three Desert Tortoise and three FLADIS two-phase ammonia jets, fifteen Thorney
|
|
130
|
+
Island instantaneous releases, two Prairie Grass passive-dispersion trials,
|
|
131
|
+
and three wind-tunnel trials. Nineteen further SMEDIS trials are excluded with
|
|
132
|
+
a recorded reason for each.
|
|
133
|
+
|
|
134
|
+
On the ten LNG trials the model passes all five Chang–Hanna criteria
|
|
135
|
+
(FAC2 0.90, MG 1.25, NMSE 0.12).
|
|
136
|
+
|
|
137
|
+
**Where it fails.** `LIMITATIONS.md` is the honest list: a known runaway for
|
|
138
|
+
dense, low-momentum releases; a stability response that four independent
|
|
139
|
+
datasets say is too strong; a hard-coded reference height that breaks Froude
|
|
140
|
+
similarity; and two published datasets for the same trials that disagree by a
|
|
141
|
+
factor of two and reverse the recommended surface roughness.
|
|
142
|
+
|
|
143
|
+
`VALIDATION.md` has the numbers and the commands that reproduce them.
|
|
144
|
+
|
|
145
|
+
## Tests
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
pytest -q
|
|
149
|
+
python3 examples/validate_burro.py # field comparison, pre-registered
|
|
150
|
+
python3 examples/diagnose_burro.py # how the hypotheses were excluded
|
|
151
|
+
python3 -c "from slabx.scope import describe_scope; print(describe_scope())"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Tests that need the original SLAB source, an optional dependency, or a
|
|
155
|
+
third-party observation are skipped when the resource is absent, so the
|
|
156
|
+
counts depend on what you have installed and obtained. Nothing fails for
|
|
157
|
+
want of them.
|
|
158
|
+
|
|
159
|
+
The one `xfailed` is deliberate: a reproducible failure kept with its input
|
|
160
|
+
deck rather than hidden.
|
|
161
|
+
|
|
162
|
+
Comparing against the original needs its source, which is not redistributable
|
|
163
|
+
here; see `golden/fortran/README.md`. Those tests skip without it and
|
|
164
|
+
everything else runs.
|
|
165
|
+
|
|
166
|
+
## Documentation
|
|
167
|
+
|
|
168
|
+
| | |
|
|
169
|
+
|---|---|
|
|
170
|
+
| `QUICKSTART.md` | install, run, change a scenario |
|
|
171
|
+
| `LIMITATIONS.md` | what it cannot do, with evidence |
|
|
172
|
+
| `VALIDATION.md` | every comparison and how to reproduce it |
|
|
173
|
+
| `docs/01_THEORY.md` | governing equations and closures |
|
|
174
|
+
| `docs/02_VALIDATION_REFERENCE.md` | agreement with the original |
|
|
175
|
+
| `docs/03_VALIDATION_FIELD.md` | agreement with measurements |
|
|
176
|
+
| `docs/04_DEVELOPMENT.md` | defects found, and the method that found them |
|
|
177
|
+
|
|
178
|
+
## Citing
|
|
179
|
+
|
|
180
|
+
Cite the version you ran -- the version DOI fixes the files, the concept DOI
|
|
181
|
+
resolves to the latest:
|
|
182
|
+
|
|
183
|
+
> Lee, U. (2026). *slabx: a Python reimplementation of the SLAB dense-gas
|
|
184
|
+
> dispersion model* (v1.0.2). Zenodo. Concept DOI
|
|
185
|
+
> [10.5281/zenodo.22023625](https://doi.org/10.5281/zenodo.22023625).
|
|
186
|
+
|
|
187
|
+
`CITATION.cff` carries the same in machine-readable form.
|
|
188
|
+
|
|
189
|
+
The model itself is Ermak's:
|
|
190
|
+
|
|
191
|
+
> Ermak, D.L. (1990) *User's Manual for SLAB: An Atmospheric Dispersion Model
|
|
192
|
+
> for Denser-than-Air Releases*. UCRL-MA-105607, Lawrence Livermore National
|
|
193
|
+
> Laboratory.
|
|
194
|
+
|
|
195
|
+
## Licence
|
|
196
|
+
|
|
197
|
+
MIT, for this implementation. `THIRD_PARTY_NOTICES.md` records the
|
|
198
|
+
third-party works relied on, none of which are included here. The original SLAB source is not included and
|
|
199
|
+
carries its own non-commercial terms; see `LICENSE` and
|
|
200
|
+
`golden/fortran/README.md`.
|
slabx-1.0.3/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# slabx
|
|
2
|
+
|
|
3
|
+
[](https://doi.org/10.5281/zenodo.22023625)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
A Python reimplementation of **SLAB**, the dense-gas dispersion model of
|
|
7
|
+
Ermak (1990, UCRL-MA-105607), verified against the original Fortran and
|
|
8
|
+
evaluated against 38 field and wind-tunnel trials.
|
|
9
|
+
|
|
10
|
+
The implementation follows the published model formulation and the user's
|
|
11
|
+
manual, in a program structure of its own; individual results were then
|
|
12
|
+
compared against the original Fortran, which was also consulted for
|
|
13
|
+
implementation details the manual leaves open. It is therefore not a
|
|
14
|
+
clean-room implementation, and the comparison points are recorded in the
|
|
15
|
+
source as line references so that the checking is visible.
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from slabx.core.plume import run_dispersion
|
|
19
|
+
from slabx.core.source import EvaporatingPool
|
|
20
|
+
from slabx.post.concentration import concentration_field
|
|
21
|
+
from slabx.submodels.atmosphere import Atmosphere
|
|
22
|
+
from slabx.thermo.base import LegacyThermo, Substance, water_backend
|
|
23
|
+
|
|
24
|
+
LNG = Substance(name="LNG", mw=0.016043, cp_vapour=2238.0, cp_liquid=3348.5,
|
|
25
|
+
dh_vap=509900.0, T_boil=111.7, rho_liquid=424.1)
|
|
26
|
+
|
|
27
|
+
atm = Atmosphere(u_ref=1.94, z_ref=3.0, T=290.0, rh=50.0, z0=2e-4,
|
|
28
|
+
stability="E")
|
|
29
|
+
|
|
30
|
+
# The pool area is the spill divided by the evaporation flux, not the
|
|
31
|
+
# footprint quoted in the manual, and the manual's worked example uses
|
|
32
|
+
# demonstration weather rather than the trial's. Both matter: the manual's
|
|
33
|
+
# 657 m2 with T = 306 K and 4.6 % humidity gives 386 m instead of 449.
|
|
34
|
+
src = EvaporatingPool(substance=LNG, rate=116.93, area=116.93 / 0.167,
|
|
35
|
+
duration=107.0)
|
|
36
|
+
|
|
37
|
+
traj, used = run_dispersion(src, atm, LegacyThermo(LNG), water_backend(),
|
|
38
|
+
x_max=2000.0, n_puff_steps=40)
|
|
39
|
+
field = concentration_field(traj, atm, z=1.0, t_avg=80.0, t_release=107.0)
|
|
40
|
+
|
|
41
|
+
print(f"{field.distance_to(0.05):.0f} m to LFL") # 449; measured 455
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`slabx.validation.lng_pools` sets all of this from the trial record, which
|
|
45
|
+
is the path the paper's numbers come from -- but it needs the observations,
|
|
46
|
+
which are not distributed here. See below.
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install -e . # numpy, scipy
|
|
52
|
+
pip install CoolProp # optional: real-fluid properties
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Python 3.10+. `QUICKSTART.md` has a runnable scenario template and a
|
|
56
|
+
troubleshooting table.
|
|
57
|
+
|
|
58
|
+
## What it does
|
|
59
|
+
|
|
60
|
+
Four source types — evaporating pool, horizontal jet, vertical jet with plume
|
|
61
|
+
rise, instantaneous release — integrated as a shallow-layer model with the
|
|
62
|
+
plume-to-puff transition of the original.
|
|
63
|
+
|
|
64
|
+
Beyond the original, all off by default so the reproduction is never disturbed:
|
|
65
|
+
|
|
66
|
+
| | |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `rainout=True` | droplet break-up, settling and removal |
|
|
69
|
+
| `kinetic_evaporation=True` | finite-rate droplet evaporation |
|
|
70
|
+
| `added_mass=True` | oblate-spheroid added mass on buoyant rise |
|
|
71
|
+
| `substrate=DRY_SOIL` | ground heat transfer |
|
|
72
|
+
| `CoolPropThermo` | real-fluid properties, and multicomponent mixtures |
|
|
73
|
+
| `meander_closure="sigma_theta"` | meander from measured wind-direction variability |
|
|
74
|
+
|
|
75
|
+
Thirty-eight coefficients are exposed as a frozen dataclass with presets, so
|
|
76
|
+
sensitivity studies do not need edits to the source.
|
|
77
|
+
|
|
78
|
+
## How far it has been checked
|
|
79
|
+
|
|
80
|
+
**Against the original Fortran.** The five decks of the manual agree to
|
|
81
|
+
0.05–1.48 % on every cloud variable, at the level of the original's own
|
|
82
|
+
discretisation error. A random differential test over 108 decks — four source
|
|
83
|
+
types, five materials, the full stability range — puts the median difference
|
|
84
|
+
at 0.09 % on temperature and 0.67 % on concentration.
|
|
85
|
+
|
|
86
|
+
The comparison is against Ermak's Fortran itself, compiled from source. Early
|
|
87
|
+
work used a JavaScript transcription and misattributed five of six differences
|
|
88
|
+
to SLAB as a result; `docs/02_VALIDATION_REFERENCE.md` §2.5 records what that
|
|
89
|
+
cost and how it was found.
|
|
90
|
+
|
|
91
|
+
**Against measurements.** Ten LNG pool trials (Burro, Coyote, Maplin Sands),
|
|
92
|
+
three Desert Tortoise and three FLADIS two-phase ammonia jets, fifteen Thorney
|
|
93
|
+
Island instantaneous releases, two Prairie Grass passive-dispersion trials,
|
|
94
|
+
and three wind-tunnel trials. Nineteen further SMEDIS trials are excluded with
|
|
95
|
+
a recorded reason for each.
|
|
96
|
+
|
|
97
|
+
On the ten LNG trials the model passes all five Chang–Hanna criteria
|
|
98
|
+
(FAC2 0.90, MG 1.25, NMSE 0.12).
|
|
99
|
+
|
|
100
|
+
**Where it fails.** `LIMITATIONS.md` is the honest list: a known runaway for
|
|
101
|
+
dense, low-momentum releases; a stability response that four independent
|
|
102
|
+
datasets say is too strong; a hard-coded reference height that breaks Froude
|
|
103
|
+
similarity; and two published datasets for the same trials that disagree by a
|
|
104
|
+
factor of two and reverse the recommended surface roughness.
|
|
105
|
+
|
|
106
|
+
`VALIDATION.md` has the numbers and the commands that reproduce them.
|
|
107
|
+
|
|
108
|
+
## Tests
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pytest -q
|
|
112
|
+
python3 examples/validate_burro.py # field comparison, pre-registered
|
|
113
|
+
python3 examples/diagnose_burro.py # how the hypotheses were excluded
|
|
114
|
+
python3 -c "from slabx.scope import describe_scope; print(describe_scope())"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Tests that need the original SLAB source, an optional dependency, or a
|
|
118
|
+
third-party observation are skipped when the resource is absent, so the
|
|
119
|
+
counts depend on what you have installed and obtained. Nothing fails for
|
|
120
|
+
want of them.
|
|
121
|
+
|
|
122
|
+
The one `xfailed` is deliberate: a reproducible failure kept with its input
|
|
123
|
+
deck rather than hidden.
|
|
124
|
+
|
|
125
|
+
Comparing against the original needs its source, which is not redistributable
|
|
126
|
+
here; see `golden/fortran/README.md`. Those tests skip without it and
|
|
127
|
+
everything else runs.
|
|
128
|
+
|
|
129
|
+
## Documentation
|
|
130
|
+
|
|
131
|
+
| | |
|
|
132
|
+
|---|---|
|
|
133
|
+
| `QUICKSTART.md` | install, run, change a scenario |
|
|
134
|
+
| `LIMITATIONS.md` | what it cannot do, with evidence |
|
|
135
|
+
| `VALIDATION.md` | every comparison and how to reproduce it |
|
|
136
|
+
| `docs/01_THEORY.md` | governing equations and closures |
|
|
137
|
+
| `docs/02_VALIDATION_REFERENCE.md` | agreement with the original |
|
|
138
|
+
| `docs/03_VALIDATION_FIELD.md` | agreement with measurements |
|
|
139
|
+
| `docs/04_DEVELOPMENT.md` | defects found, and the method that found them |
|
|
140
|
+
|
|
141
|
+
## Citing
|
|
142
|
+
|
|
143
|
+
Cite the version you ran -- the version DOI fixes the files, the concept DOI
|
|
144
|
+
resolves to the latest:
|
|
145
|
+
|
|
146
|
+
> Lee, U. (2026). *slabx: a Python reimplementation of the SLAB dense-gas
|
|
147
|
+
> dispersion model* (v1.0.2). Zenodo. Concept DOI
|
|
148
|
+
> [10.5281/zenodo.22023625](https://doi.org/10.5281/zenodo.22023625).
|
|
149
|
+
|
|
150
|
+
`CITATION.cff` carries the same in machine-readable form.
|
|
151
|
+
|
|
152
|
+
The model itself is Ermak's:
|
|
153
|
+
|
|
154
|
+
> Ermak, D.L. (1990) *User's Manual for SLAB: An Atmospheric Dispersion Model
|
|
155
|
+
> for Denser-than-Air Releases*. UCRL-MA-105607, Lawrence Livermore National
|
|
156
|
+
> Laboratory.
|
|
157
|
+
|
|
158
|
+
## Licence
|
|
159
|
+
|
|
160
|
+
MIT, for this implementation. `THIRD_PARTY_NOTICES.md` records the
|
|
161
|
+
third-party works relied on, none of which are included here. The original SLAB source is not included and
|
|
162
|
+
carries its own non-commercial terms; see `LICENSE` and
|
|
163
|
+
`golden/fortran/README.md`.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "slabx"
|
|
7
|
+
version = "1.0.3"
|
|
8
|
+
description = "A Python reimplementation of the SLAB dense-gas dispersion model, verified against the original and evaluated against field and wind-tunnel trials"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Ugwiyeon Lee", email = "lyullee@kgs.or.kr" },
|
|
15
|
+
]
|
|
16
|
+
keywords = [
|
|
17
|
+
"dense gas dispersion",
|
|
18
|
+
"atmospheric dispersion",
|
|
19
|
+
"model validation",
|
|
20
|
+
"SLAB",
|
|
21
|
+
"process safety",
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 5 - Production/Stable",
|
|
25
|
+
"Intended Audience :: Science/Research",
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
"Programming Language :: Python :: 3",
|
|
28
|
+
"Programming Language :: Python :: 3.10",
|
|
29
|
+
"Programming Language :: Python :: 3.11",
|
|
30
|
+
"Programming Language :: Python :: 3.12",
|
|
31
|
+
"Programming Language :: Python :: 3.13",
|
|
32
|
+
"Topic :: Scientific/Engineering :: Atmospheric Science",
|
|
33
|
+
"Topic :: Scientific/Engineering :: Physics",
|
|
34
|
+
]
|
|
35
|
+
dependencies = [
|
|
36
|
+
"numpy>=1.24",
|
|
37
|
+
"scipy>=1.10",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://github.com/lyullee/slabx"
|
|
42
|
+
Repository = "https://github.com/lyullee/slabx"
|
|
43
|
+
Documentation = "https://github.com/lyullee/slabx#readme"
|
|
44
|
+
Issues = "https://github.com/lyullee/slabx/issues"
|
|
45
|
+
"Archived version" = "https://doi.org/10.5281/zenodo.22023625"
|
|
46
|
+
|
|
47
|
+
[project.optional-dependencies]
|
|
48
|
+
thermo = ["CoolProp>=6.5"]
|
|
49
|
+
data = ["pandas>=2.0", "xarray>=2023.1"]
|
|
50
|
+
dev = ["pytest>=7.4", "pytest-cov"]
|
|
51
|
+
|
|
52
|
+
[tool.setuptools.packages.find]
|
|
53
|
+
where = ["src"]
|
|
54
|
+
|
|
55
|
+
[tool.pytest.ini_options]
|
|
56
|
+
testpaths = ["tests"]
|
|
57
|
+
pythonpath = ["src"]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
[tool.setuptools.package-data]
|
|
61
|
+
# Only our own files. Third-party observations are never inside the package
|
|
62
|
+
# -- they are looked for under $SLABX_VALIDATION_DATA -- so there is nothing
|
|
63
|
+
# here that could carry them into a wheel or an sdist by accident.
|
|
64
|
+
"slabx.validation" = [
|
|
65
|
+
"data/provenance/*.csv",
|
|
66
|
+
"data/provenance/*.md",
|
|
67
|
+
"data/smedis_inventory.csv",
|
|
68
|
+
]
|
slabx-1.0.3/setup.cfg
ADDED
|
File without changes
|