Skip to content

Commit

Permalink
Merge pull request #790 from slayoo/fixes
Browse files Browse the repository at this point in the history
BDF condensation in pyrcel smoke tests + work in progress on more test coverage for condensation
  • Loading branch information
slayoo authored May 3, 2022
2 parents 70cdc83 + c7e4827 commit 20301d7
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ repos:
- id: isort

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0
rev: v4.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand Down
4 changes: 2 additions & 2 deletions PySDM/products/size_spectral/water_mixing_ratio.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@


class WaterMixingRatio(MomentProduct):
def __init__(self, radius_range=(0, np.inf), name=None, unit="dimensionless"):
self.radius_range = radius_range
def __init__(self, radius_range=None, name=None, unit="dimensionless"):
self.radius_range = radius_range or (0, np.inf)
self.volume_range = None
super().__init__(unit=unit, name=name)

Expand Down
2 changes: 1 addition & 1 deletion test-time-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ ghapi
pytest

# note: if cloning both PySDM and PySDM examples, consider "pip install -e"
PySDM-examples @ git+https://github.com/slayoo/PySDM-examples@35f25d1#egg=PySDM-examples
PySDM-examples @ git+https://github.com/atmos-cloud-sim-uj/PySDM-examples@7ad7cd0#egg=PySDM-examples
PyMPDATA @ git+https://github.com/atmos-cloud-sim-uj/PyMPDATA@e7b73a7#egg=PyMPDATA
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
import numpy as np
import pytest
from matplotlib import pyplot
from scipy import signal

from PySDM import Builder
from PySDM import products as PySDM_products
from PySDM.backends import CPU
from PySDM.backends.impl_numba.test_helpers import bdf
from PySDM.dynamics import AmbientThermodynamics, Condensation
from PySDM.environments import Parcel
from PySDM.initialisation import equilibrate_wet_radii
from PySDM.initialisation.sampling.spectral_sampling import ConstantMultiplicity
from PySDM.initialisation.spectra import Lognormal
from PySDM.physics import si


@pytest.mark.parametrize(
"rtol_thd",
(
pytest.param(1e-6, marks=pytest.mark.xfail(strict=True)),
pytest.param(1e-7, marks=pytest.mark.xfail(strict=True)),
1e-8,
1e-9,
),
)
@pytest.mark.parametrize("rtol_x", (1e-7,))
@pytest.mark.parametrize("adaptive", (True,))
@pytest.mark.parametrize("scheme", ("PySDM",))
def test_single_supersaturation_peak(adaptive, scheme, rtol_x, rtol_thd, plot=False):
# arrange
products = (
PySDM_products.WaterMixingRatio(unit="g/kg", name="ql"),
PySDM_products.PeakSupersaturation(name="S max"),
PySDM_products.AmbientRelativeHumidity(name="RH"),
PySDM_products.ParcelDisplacement(name="z"),
)
env = Parcel(
dt=2 * si.s,
mass_of_dry_air=1e3 * si.kg,
p0=1000 * si.hPa,
q0=22.76 * si.g / si.kg,
w=0.5 * si.m / si.s,
T0=300 * si.K,
)
n_steps = 70
n_sd = 2
kappa = 0.4
spectrum = Lognormal(norm_factor=5000 / si.cm**3, m_mode=50.0 * si.nm, s_geom=2.0)
builder = Builder(backend=CPU(), n_sd=n_sd)
builder.set_environment(env)
builder.add_dynamic(AmbientThermodynamics())
builder.add_dynamic(
Condensation(
adaptive=adaptive,
rtol_x=rtol_x,
rtol_thd=rtol_thd,
)
)

r_dry, concentration = ConstantMultiplicity(spectrum).sample(n_sd)
v_dry = builder.formulae.trivia.volume(radius=r_dry)
r_wet = equilibrate_wet_radii(
r_dry=r_dry, environment=env, kappa_times_dry_volume=kappa * v_dry
)
specific_concentration = concentration / builder.formulae.constants.rho_STP
attributes = {
"n": specific_concentration * env.mass_of_dry_air,
"dry volume": v_dry,
"kappa times dry volume": kappa * v_dry,
"volume": builder.formulae.trivia.volume(radius=r_wet),
}

particulator = builder.build(attributes, products=products)

if scheme == "BDF":
bdf.patch_particulator(particulator)

output = {product.name: [] for product in particulator.products.values()}
output_attributes = {"volume": tuple([] for _ in range(particulator.n_sd))}

# act
for _ in range(n_steps):
particulator.run(steps=1)
for product in particulator.products.values():
value = product.get()
output[product.name].append(value[0])
for key, attr in output_attributes.items():
attr_data = particulator.attributes[key].to_ndarray()
for drop_id in range(particulator.n_sd):
attr[drop_id].append(attr_data[drop_id])

# plot
for drop_id, volume in enumerate(output_attributes["volume"]):
pyplot.semilogx(
particulator.formulae.trivia.radius(volume=np.asarray(volume)) / si.um,
output["z"],
color="black",
label="drop size (bottom axis)",
)
pyplot.xlabel("radius [um]")
pyplot.ylabel("z [m]")
twin = pyplot.twiny()
twin.plot(output["S max"], output["z"], label="S max (top axis)")
twin.plot(np.asarray(output["RH"]) - 1, output["z"], label="ambient RH (top axis)")
twin.legend(loc="upper center")
twin.set_xlim(-0.001, 0.0015)
pyplot.legend(loc="lower right")
pyplot.grid()
pyplot.title(f"rtol_thd={rtol_thd}; rtol_x={rtol_x}")
if plot:
pyplot.show()

# assert
assert signal.argrelextrema(np.asarray(output["RH"]), np.greater)[0].shape[0] == 1
12 changes: 8 additions & 4 deletions tests/smoke_tests/lowe_et_al_2019/test_fig_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,13 @@ def test_peak_supersaturation_and_final_concentration(
*, constants, aerosol, surface_tension, s_max, s_100m, n_100m
):
# arrange
dt = 1 * si.s
w = 0.32 * si.m / si.s
z_max = 200 * si.m
n_steps = int(z_max / w / dt)
dz = z_max / n_steps
settings = Settings(
dz=2 / 0.32 * si.m,
dz=dz,
n_sd_per_mode=32,
model=surface_tension,
aerosol=aerosol,
Expand All @@ -44,9 +49,8 @@ def test_peak_supersaturation_and_final_concentration(
output = simulation.run()

# assert
# assert len(output['S_max']) == 2
i_100m = 312
# print(output["z"][i_100m])
i_100m = np.argmin(np.abs(np.asarray(output["z"]) - 100 * si.m))
print(i_100m, output["z"][i_100m])
print(np.nanmax(output["S_max"]), s_max)
print(output["S_max"][i_100m], s_100m)
print(output["n_c_cm3"][i_100m], n_100m)
Expand Down
26 changes: 17 additions & 9 deletions tests/smoke_tests/pyrcel/test_parcel_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@
from PySDM import Formulae
from PySDM.initialisation.spectra import Lognormal
from PySDM.physics import si
from PySDM.products import AmbientTemperature, ParcelDisplacement, PeakSupersaturation
from PySDM.products import (
AmbientRelativeHumidity,
AmbientTemperature,
ParcelDisplacement,
)


class TestParcelExample:
@staticmethod
@pytest.mark.parametrize("s_max, s_250m, T_250m", ((0.62, 0.139, 272.2),))
@pytest.mark.xfail(strict=True) # TODO #776
# pylint: disable=redefined-outer-name,unused-argument
def test_supersaturation_and_temperature_profile(s_max, s_250m, T_250m):
@pytest.mark.parametrize("scipy_solver", (pytest.param(True), pytest.param(False)))
def test_supersaturation_and_temperature_profile(
s_max, s_250m, T_250m, scipy_solver
):
# arrange
settings = Settings(
dz=1 * si.m,
Expand All @@ -38,21 +43,24 @@ def test_supersaturation_and_temperature_profile(s_max, s_250m, T_250m):
settings,
products=(
ParcelDisplacement(name="z"),
PeakSupersaturation(name="S_max", unit="%"),
AmbientRelativeHumidity(name="RH", unit="%"),
AmbientTemperature(name="T"),
),
scipy_solver=scipy_solver,
)

# act
output = simulation.run()

# assert
np.testing.assert_approx_equal(
np.nanmax(output["products"]["S_max"]), s_max, significant=2
)
np.testing.assert_approx_equal(
output["products"]["S_max"][-1], s_250m, significant=2
np.nanmax(np.asarray(output["products"]["RH"])) - 100, s_max, significant=2
)

np.testing.assert_approx_equal(
output["products"]["T"][-1], T_250m, significant=2
)

# TODO #776
# np.testing.assert_approx_equal(output['products']['RH'][-1]-100, s_250m, significant=2)
assert s_250m is not None

0 comments on commit 20301d7

Please sign in to comment.