Skip to content

Commit d4d393c

Browse files
authored
fix Mv constant calc (D and T abundances count twice in water molecular abundances); share initial parameters across J&N and Yang examples (#1258)
1 parent 0fd927f commit d4d393c

File tree

8 files changed

+2840
-52
lines changed

8 files changed

+2840
-52
lines changed

PySDM/physics/constants_defaults.py

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
)
3939

4040
# https://web.archive.org/web/20200729203147/https://nucleus.iaea.org/rpst/documents/VSMOW_SLAP.pdf
41+
# heavy-to-light isotope abundance ratios
4142
VSMOW_R_2H = 155.76 * PPM
4243
VSMOW_R_3H = 1.85e-11 * PPM
4344
VSMOW_R_18O = 2005.20 * PPM
@@ -53,19 +54,6 @@
5354
M_17O = 16.99913175651 * si.g / si.mole
5455
M_18O = 17.99915961287 * si.g / si.mole
5556

56-
Mv = (
57-
1
58-
- Trivia.mixing_ratio_to_specific_content(
59-
VSMOW_R_2H / 2 + VSMOW_R_3H / 2 + VSMOW_R_17O + VSMOW_R_18O
60-
)
61-
) * (
62-
(M_1H * 2 + M_16O)
63-
+ (M_2H + M_1H + M_16O) * VSMOW_R_2H
64-
+ (M_3H + M_1H + M_16O) * VSMOW_R_3H
65-
+ (M_1H * 2 + M_17O) * VSMOW_R_17O
66-
+ (M_1H * 2 + M_18O) * VSMOW_R_18O
67-
)
68-
6957
R_str = sci.R * si.joule / si.kelvin / si.mole
7058
N_A = sci.N_A / si.mole
7159

@@ -356,6 +344,39 @@
356344

357345

358346
def compute_derived_values(c: dict):
347+
"""
348+
computes derived quantities such as molar mass ratios, etc.
349+
350+
water molar mass is computed from from molecular masses and VSMOW isotope abundances
351+
(and neglecting molecular binding energies)
352+
for discussion, see:
353+
- caption of Table 2.1 in [Gat 2010](https://doi.org/10.1142/p027)
354+
- [IAPWS Guidelines](http://www.iapws.org/relguide/fundam.pdf)
355+
"""
356+
357+
c["Mv"] = (
358+
(
359+
1
360+
- 2 * Trivia.mixing_ratio_to_specific_content(c["VSMOW_R_2H"])
361+
- 2 * Trivia.mixing_ratio_to_specific_content(c["VSMOW_R_3H"])
362+
- 1 * Trivia.mixing_ratio_to_specific_content(c["VSMOW_R_17O"])
363+
- 1 * Trivia.mixing_ratio_to_specific_content(c["VSMOW_R_18O"])
364+
)
365+
* (c["M_1H"] * 2 + c["M_16O"])
366+
+ 2
367+
* Trivia.mixing_ratio_to_specific_content(c["VSMOW_R_2H"])
368+
* (c["M_2H"] + c["M_1H"] + c["M_16O"])
369+
+ 2
370+
* Trivia.mixing_ratio_to_specific_content(c["VSMOW_R_3H"])
371+
* (c["M_3H"] + c["M_1H"] + c["M_16O"])
372+
+ 1
373+
* Trivia.mixing_ratio_to_specific_content(c["VSMOW_R_17O"])
374+
* (c["M_1H"] * 2 + c["M_17O"])
375+
+ 1
376+
* Trivia.mixing_ratio_to_specific_content(c["VSMOW_R_18O"])
377+
* (c["M_1H"] * 2 + c["M_18O"])
378+
)
379+
359380
c["eps"] = c["Mv"] / c["Md"]
360381
c["Rd"] = c["R_str"] / c["Md"]
361382
c["Rv"] = c["R_str"] / c["Mv"]

examples/PySDM_examples/Jensen_and_Nugent_2017/settings.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@
33
from PySDM.physics import si
44
from PySDM.initialisation.spectra import Lognormal, Sum
55

6+
INITIAL_RELATIVE_HUMIDITY = 0.8561
7+
INITIAL_TEMPERATURE = 284.3 * si.K
8+
INITIAL_PRESSURE = 938.5 * si.hPa
9+
INITIAL_ALTITUDE = 600 * si.metres
10+
611

712
@strict
813
class Settings:
914
def __init__(self, *, aerosol: str, cloud_type: str):
10-
# TODO #1266 reuse these values in the Yang et al. '18 example which is based on J&N'16
11-
self.p0 = 938.5 * si.hPa
12-
self.RH0 = 0.8561
13-
self.T0 = 284.3 * si.K
14-
self.z0 = 600 * si.m
15+
self.p0 = INITIAL_PRESSURE
16+
self.RH0 = INITIAL_RELATIVE_HUMIDITY
17+
self.T0 = INITIAL_TEMPERATURE
18+
self.z0 = INITIAL_ALTITUDE
1519
self.t_end_of_ascent = 1500 * si.s if cloud_type == "Sc" else None
1620
self.dt = 1 * si.s # TODO #1266: not found in the paper yet
1721

examples/PySDM_examples/Yang_et_al_2018/fig_2.ipynb

Lines changed: 2776 additions & 24 deletions
Large diffs are not rendered by default.

examples/PySDM_examples/Yang_et_al_2018/settings.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import numpy as np
22
from pystrict import strict
33

4+
from PySDM_examples import Jensen_and_Nugent_2017
5+
46
from PySDM.backends import CPU
57
from PySDM.dynamics import condensation
68
from PySDM.initialisation import spectra
@@ -47,10 +49,10 @@ def __init__(
4749
self.rtol_thd = condensation.DEFAULTS.rtol_thd
4850
self.dt_cond_range = condensation.DEFAULTS.cond_range
4951

50-
self.T0 = 284.3 * si.kelvin
51-
self.initial_water_vapour_mixing_ratio = 7.6 * si.grams / si.kilogram
52-
self.p0 = 938.5 * si.hectopascals
53-
self.z0 = 600 * si.metres
52+
self.T0 = Jensen_and_Nugent_2017.settings.INITIAL_TEMPERATURE
53+
self.RH0 = Jensen_and_Nugent_2017.settings.INITIAL_RELATIVE_HUMIDITY
54+
self.p0 = Jensen_and_Nugent_2017.settings.INITIAL_PRESSURE
55+
self.z0 = Jensen_and_Nugent_2017.settings.INITIAL_ALTITUDE
5456
self.kappa = 0.53 # Petters and S. M. Kreidenweis mean growth-factor derived
5557

5658
self.t0 = 1200 * si.second

examples/PySDM_examples/Yang_et_al_2018/simulation.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,15 @@ def __init__(self, settings, backend=CPU):
2626
dt=dt_output / self.n_substeps,
2727
mass_of_dry_air=settings.mass_of_dry_air,
2828
p0=settings.p0,
29-
initial_water_vapour_mixing_ratio=settings.initial_water_vapour_mixing_ratio,
29+
initial_water_vapour_mixing_ratio=self.formulae.constants.eps
30+
/ (
31+
settings.p0
32+
/ settings.RH0
33+
/ self.formulae.saturation_vapour_pressure.pvs_Celsius(
34+
settings.T0 - self.formulae.constants.T0
35+
)
36+
- 1
37+
),
3038
T0=settings.T0,
3139
w=settings.w,
3240
z0=settings.z0,

tests/smoke_tests/parcel/yang_et_al_2018/test_initialisation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,4 @@ def test_relative_humidity():
8080
simulation = Simulation(settings)
8181

8282
# Assert
83-
assert round(simulation.particulator.environment["RH"][0], 3) == 0.859
83+
assert round(simulation.particulator.environment["RH"][0], 3) == 0.856

tests/unit_tests/initialisation/test_aerosol_init.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from chempy import Substance
55

66
# from PySDM.initialisation import spectra
7+
from PySDM import Formulae
78
from PySDM.initialisation.aerosol_composition import DryAerosolMixture
8-
from PySDM.physics import constants_defaults as const
99
from PySDM.physics import si
1010

1111

@@ -19,6 +19,7 @@
1919
)
2020
def test_volume_weighted_kappa_with_insoluble_compound(mass_fractions):
2121
# Arrange
22+
const = Formulae().constants
2223
water_molar_volume = const.Mv / const.rho_w
2324
compounds = ("(NH4)2SO4", "insoluble")
2425
molar_masses = {

tests/unit_tests/physics/test_constants.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@ def test_isotope_molar_masses_vs_wikipedia_or_scipy(item, value):
118118
@staticmethod
119119
def test_isotope_molar_masses_vsmow_vs_mean_water_molar_mass():
120120
np.testing.assert_approx_equal(
121-
desired=constants_defaults.Mv,
122-
actual=Substance.from_formula("H2O").mass * si.gram / si.mole,
123-
significant=4.5,
121+
actual=Formulae().constants.Mv,
122+
desired=Substance.from_formula("H2O").mass * si.gram / si.mole,
123+
significant=5.5,
124124
)
125125

126126
@staticmethod

0 commit comments

Comments
 (0)