lh2poolx 0.1.0__py3-none-any.whl
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.
- lh2poolx/__init__.py +19 -0
- lh2poolx/pool.py +148 -0
- lh2poolx-0.1.0.dist-info/METADATA +92 -0
- lh2poolx-0.1.0.dist-info/RECORD +6 -0
- lh2poolx-0.1.0.dist-info/WHEEL +4 -0
- lh2poolx-0.1.0.dist-info/licenses/LICENSE +21 -0
lh2poolx/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Evidence-qualified LH2 pool source terms for dispersion-model inputs."""
|
|
2
|
+
|
|
3
|
+
from .pool import (
|
|
4
|
+
CONCRETE_CRYOGENIC,
|
|
5
|
+
CRITICAL_HEAT_FLUX_W_M2,
|
|
6
|
+
LH2Release,
|
|
7
|
+
PoolSource,
|
|
8
|
+
Substrate,
|
|
9
|
+
evaluate_pool_source,
|
|
10
|
+
flash_vapour_fraction,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"__version__", "CONCRETE_CRYOGENIC", "CRITICAL_HEAT_FLUX_W_M2",
|
|
17
|
+
"LH2Release", "PoolSource", "Substrate", "evaluate_pool_source",
|
|
18
|
+
"flash_vapour_fraction",
|
|
19
|
+
]
|
lh2poolx/pool.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""Quasi-steady LH2 pool source terms with explicit evidence boundaries."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
import math
|
|
7
|
+
|
|
8
|
+
import CoolProp.CoolProp as CP
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
CRITICAL_HEAT_FLUX_W_M2 = 120e3
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class Substrate:
|
|
16
|
+
"""Effective cryogenic substrate properties for the stated evidence case."""
|
|
17
|
+
|
|
18
|
+
name: str
|
|
19
|
+
conductivity_W_mK: float
|
|
20
|
+
diffusivity_m2_s: float
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# PRESLHY E3.4 Concrete02 effective cryogenic properties. Do not use this as
|
|
24
|
+
# a generic concrete correlation without an explicit applicability decision.
|
|
25
|
+
CONCRETE_CRYOGENIC = Substrate("concrete_cryogenic_e34", 2.0, 2.5e-7)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class LH2Release:
|
|
30
|
+
"""Declared inputs for an LH2 release reaching a possible ground pool."""
|
|
31
|
+
|
|
32
|
+
rate_kg_s: float
|
|
33
|
+
storage_pressure_barg: float
|
|
34
|
+
deposition_fraction: float = 1.0
|
|
35
|
+
max_radius_m: float | None = None
|
|
36
|
+
|
|
37
|
+
def __post_init__(self) -> None:
|
|
38
|
+
if self.rate_kg_s <= 0.0:
|
|
39
|
+
raise ValueError("rate_kg_s must be > 0")
|
|
40
|
+
if self.storage_pressure_barg < 0.0:
|
|
41
|
+
raise ValueError("storage_pressure_barg must be >= 0")
|
|
42
|
+
if not 0.0 <= self.deposition_fraction <= 1.0:
|
|
43
|
+
raise ValueError("deposition_fraction must be in [0, 1]")
|
|
44
|
+
if self.max_radius_m is not None and self.max_radius_m <= 0.0:
|
|
45
|
+
raise ValueError("max_radius_m must be > 0 when supplied")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass(frozen=True)
|
|
49
|
+
class PoolSource:
|
|
50
|
+
"""A source term for one declared time window, not a pool trajectory."""
|
|
51
|
+
|
|
52
|
+
elapsed_s: float
|
|
53
|
+
flash_vapour_fraction: float
|
|
54
|
+
deposition_fraction: float
|
|
55
|
+
liquid_to_ground_kg_s: float
|
|
56
|
+
pool_temperature_K: float
|
|
57
|
+
latent_heat_J_kg: float
|
|
58
|
+
evaporative_flux_kg_m2_s: float
|
|
59
|
+
unconfined_radius_m: float
|
|
60
|
+
radius_m: float
|
|
61
|
+
area_m2: float
|
|
62
|
+
evaporation_rate_kg_s: float
|
|
63
|
+
liquid_accumulation_rate_kg_s: float
|
|
64
|
+
confined: bool
|
|
65
|
+
source_status: str
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def flash_vapour_fraction(storage_pressure_barg: float, *,
|
|
69
|
+
ambient_pressure_Pa: float = 101325.0) -> float:
|
|
70
|
+
"""Isenthalpic saturated-liquid LH2 flash fraction at ambient pressure."""
|
|
71
|
+
if storage_pressure_barg < 0.0:
|
|
72
|
+
raise ValueError("storage_pressure_barg must be >= 0")
|
|
73
|
+
p0 = storage_pressure_barg * 1e5 + ambient_pressure_Pa
|
|
74
|
+
if p0 >= CP.PropsSI("Pcrit", "Hydrogen"):
|
|
75
|
+
raise ValueError("storage pressure is at or above H2 critical pressure")
|
|
76
|
+
h0 = CP.PropsSI("H", "P", p0, "Q", 0, "Hydrogen")
|
|
77
|
+
x = CP.PropsSI("Q", "P", ambient_pressure_Pa, "H", h0, "Hydrogen")
|
|
78
|
+
return min(max(float(x), 0.0), 1.0)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _ground_flux(*, substrate: Substrate, latent_heat_J_kg: float,
|
|
82
|
+
ambient_temperature_K: float, pool_temperature_K: float,
|
|
83
|
+
elapsed_s: float,
|
|
84
|
+
critical_heat_flux_W_m2: float | None) -> float:
|
|
85
|
+
if elapsed_s <= 0.0:
|
|
86
|
+
raise ValueError("elapsed_s must be > 0")
|
|
87
|
+
if latent_heat_J_kg <= 0.0:
|
|
88
|
+
raise ValueError("latent_heat_J_kg must be > 0")
|
|
89
|
+
if critical_heat_flux_W_m2 is not None and critical_heat_flux_W_m2 <= 0.0:
|
|
90
|
+
raise ValueError("critical_heat_flux_W_m2 must be > 0 or None")
|
|
91
|
+
delta_T = ambient_temperature_K - pool_temperature_K
|
|
92
|
+
if delta_T <= 0.0:
|
|
93
|
+
return 0.0
|
|
94
|
+
q = substrate.conductivity_W_mK * delta_T / math.sqrt(
|
|
95
|
+
math.pi * substrate.diffusivity_m2_s * elapsed_s
|
|
96
|
+
)
|
|
97
|
+
if critical_heat_flux_W_m2 is not None:
|
|
98
|
+
q = min(q, critical_heat_flux_W_m2)
|
|
99
|
+
return q / latent_heat_J_kg
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def evaluate_pool_source(release: LH2Release, *, elapsed_s: float,
|
|
103
|
+
substrate: Substrate = CONCRETE_CRYOGENIC,
|
|
104
|
+
ambient_temperature_K: float = 282.0,
|
|
105
|
+
ambient_pressure_Pa: float = 101325.0,
|
|
106
|
+
critical_heat_flux_W_m2: float | None =
|
|
107
|
+
CRITICAL_HEAT_FLUX_W_M2) -> PoolSource:
|
|
108
|
+
"""Calculate a quasi-steady pool source for one elapsed-time window.
|
|
109
|
+
|
|
110
|
+
The pool area instantaneously balances the declared liquid-to-ground rate
|
|
111
|
+
against heat-limited evaporation. This is appropriate only after a pool
|
|
112
|
+
exists and where a quasi-steady source approximation is justified.
|
|
113
|
+
"""
|
|
114
|
+
x = flash_vapour_fraction(release.storage_pressure_barg,
|
|
115
|
+
ambient_pressure_Pa=ambient_pressure_Pa)
|
|
116
|
+
T_pool = float(CP.PropsSI("T", "P", ambient_pressure_Pa, "Q", 0,
|
|
117
|
+
"Hydrogen"))
|
|
118
|
+
latent = float(CP.PropsSI("H", "P", ambient_pressure_Pa, "Q", 1,
|
|
119
|
+
"Hydrogen") - CP.PropsSI(
|
|
120
|
+
"H", "P", ambient_pressure_Pa, "Q", 0,
|
|
121
|
+
"Hydrogen"))
|
|
122
|
+
flux = _ground_flux(
|
|
123
|
+
substrate=substrate, latent_heat_J_kg=latent,
|
|
124
|
+
ambient_temperature_K=ambient_temperature_K,
|
|
125
|
+
pool_temperature_K=T_pool, elapsed_s=elapsed_s,
|
|
126
|
+
critical_heat_flux_W_m2=critical_heat_flux_W_m2,
|
|
127
|
+
)
|
|
128
|
+
liquid_to_ground = release.rate_kg_s * (1.0 - x) * release.deposition_fraction
|
|
129
|
+
radius_unconfined = (0.0 if liquid_to_ground == 0.0 else math.sqrt(
|
|
130
|
+
liquid_to_ground / (math.pi * flux)))
|
|
131
|
+
radius = radius_unconfined if release.max_radius_m is None else min(
|
|
132
|
+
radius_unconfined, release.max_radius_m)
|
|
133
|
+
area = math.pi * radius * radius
|
|
134
|
+
evaporation = area * flux
|
|
135
|
+
confined = (release.max_radius_m is not None and
|
|
136
|
+
radius_unconfined > release.max_radius_m)
|
|
137
|
+
return PoolSource(
|
|
138
|
+
elapsed_s=elapsed_s, flash_vapour_fraction=x,
|
|
139
|
+
deposition_fraction=release.deposition_fraction,
|
|
140
|
+
liquid_to_ground_kg_s=liquid_to_ground, pool_temperature_K=T_pool,
|
|
141
|
+
latent_heat_J_kg=latent, evaporative_flux_kg_m2_s=flux,
|
|
142
|
+
unconfined_radius_m=radius_unconfined, radius_m=radius, area_m2=area,
|
|
143
|
+
evaporation_rate_kg_s=evaporation,
|
|
144
|
+
liquid_accumulation_rate_kg_s=max(liquid_to_ground - evaporation, 0.0),
|
|
145
|
+
confined=confined,
|
|
146
|
+
source_status=("quasi_steady_equilibrium" if not confined else
|
|
147
|
+
"confined_pool_requires_inventory_model"),
|
|
148
|
+
)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: lh2poolx
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Transparent liquid-hydrogen pool source terms for dispersion models
|
|
5
|
+
Project-URL: Source, https://github.com/lyullee/lh2poolx
|
|
6
|
+
Project-URL: Documentation, https://github.com/lyullee/lh2poolx#readme
|
|
7
|
+
Author: Ugwiyeon Lee
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 Ugwiyeon Lee
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Keywords: LH2,liquid hydrogen,pool evaporation,process safety,source term
|
|
31
|
+
Classifier: Development Status :: 3 - Alpha
|
|
32
|
+
Classifier: Intended Audience :: Science/Research
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Programming Language :: Python :: 3
|
|
35
|
+
Classifier: Topic :: Scientific/Engineering
|
|
36
|
+
Requires-Python: >=3.10
|
|
37
|
+
Requires-Dist: coolprop>=6.5
|
|
38
|
+
Provides-Extra: test
|
|
39
|
+
Requires-Dist: pytest>=7; extra == 'test'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# LH2PoolX
|
|
43
|
+
|
|
44
|
+
LH2PoolX calculates an **evidence-qualified, quasi-steady liquid-hydrogen
|
|
45
|
+
pool source term** for a declared time window. It is an upstream input module
|
|
46
|
+
for dispersion models, not a dispersion model and not a general jet-impact or
|
|
47
|
+
pool-spreading solver.
|
|
48
|
+
|
|
49
|
+
## What it calculates
|
|
50
|
+
|
|
51
|
+
For a specified release rate, storage pressure, elapsed time, substrate and
|
|
52
|
+
ground-deposition fraction, LH2PoolX calculates:
|
|
53
|
+
|
|
54
|
+
1. isenthalpic flash fraction using CoolProp;
|
|
55
|
+
2. liquid mass reaching the ground;
|
|
56
|
+
3. heat-limited evaporation flux using a semi-infinite ground-conduction
|
|
57
|
+
relation with an LH2 critical-heat-flux cap; and
|
|
58
|
+
4. the unconfined equilibrium pool area and evaporation rate.
|
|
59
|
+
|
|
60
|
+
`deposition_fraction` is deliberately explicit. The package does **not**
|
|
61
|
+
predict impingement, splashing, droplet transport, drainage, barriers, or
|
|
62
|
+
transient pool spreading. A confined result reports liquid accumulation and
|
|
63
|
+
must not be used as a steady source without a separate inventory model.
|
|
64
|
+
|
|
65
|
+
## Install
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install lh2poolx
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Minimal use
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from lh2poolx import LH2Release, evaluate_pool_source
|
|
75
|
+
|
|
76
|
+
release = LH2Release(rate_kg_s=0.1055, storage_pressure_barg=1.0)
|
|
77
|
+
source = evaluate_pool_source(release, elapsed_s=300.0)
|
|
78
|
+
print(source.area_m2, source.evaporation_rate_kg_s)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Evidence boundary
|
|
82
|
+
|
|
83
|
+
The concrete heat-transfer implementation is checked against the four
|
|
84
|
+
published PRESLHY E3.4 Concrete02 mass-loss windows. That comparison is a
|
|
85
|
+
restricted substrate-and-condition check, not validation for other substrates
|
|
86
|
+
or for jet-to-ground deposition. Literature supports the physical form of
|
|
87
|
+
the source chain; it does not turn unknown deposition into a fitted value.
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MIT. Cite the accompanying software record when one is released, plus the
|
|
92
|
+
underlying experimental and heat-transfer sources used in an analysis.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
lh2poolx/__init__.py,sha256=UwGw6FCZbN7Wd1EIx5pSktT8StTnPllPgwewDCEriEc,456
|
|
2
|
+
lh2poolx/pool.py,sha256=AexRFuWbCQmJMyfIy1Hzc07WY2Vm9D5C7YEwus9e3VA,6078
|
|
3
|
+
lh2poolx-0.1.0.dist-info/METADATA,sha256=ngOmnjJYaevbSXBlIqAjLb5GiYLKOKIXLUw-S6OEsCo,3850
|
|
4
|
+
lh2poolx-0.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
5
|
+
lh2poolx-0.1.0.dist-info/licenses/LICENSE,sha256=1NqdQIjRYLmcIHzB2vXntniTEiavLqsAoyiAabNdWtQ,1069
|
|
6
|
+
lh2poolx-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
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.
|