Skip to content

Commit 063feed

Browse files
authored
surface precip product compatibility in S&H example and netCDF exporter + fix in CI examples-setup editable instal (#1322)
1 parent afeda37 commit 063feed

File tree

6 files changed

+151
-115
lines changed

6 files changed

+151
-115
lines changed

.github/workflows/tests+artifacts+pypi.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ jobs:
198198
- if: steps.cache.outputs.cache-hit != 'true'
199199
run: |
200200
python -m pip uninstall -y jupyterlab-server # https://github.com/pypa/pip/issues/6275
201-
python -m pip install -e . ./examples
201+
python -m pip install -e . -e ./examples
202202
python -m pip install -r tests/devops_tests/requirements.txt
203203
- if: steps.cache.outputs.cache-hit != 'true'
204204
uses: actions/cache/save@v4

PySDM/exporters/netcdf_exporter_1d.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ def _create_variables(self, ncdf):
7575
)
7676

7777
n_dimensions = len(instance.shape)
78-
if n_dimensions == 1:
78+
if n_dimensions == 0:
79+
dimensions = ("time",)
80+
elif n_dimensions == 1:
7981
dimensions = ("height", "time")
8082
elif n_dimensions == 2:
8183
dim_name = name.replace(" ", "_") + "_bin_index"
@@ -94,7 +96,9 @@ def _create_variables(self, ncdf):
9496
def _write_variables(self):
9597
for var in self.simulator.particulator.products.keys():
9698
n_dimensions = len(self.simulator.particulator.products[var].shape)
97-
if n_dimensions == 1:
99+
if n_dimensions == 0:
100+
self.vars[var][:] = self.data[var][:]
101+
elif n_dimensions == 1:
98102
self.vars[var][:, :] = self.data[var][-self.nz_export :, :]
99103
elif n_dimensions == 2:
100104
if self.n_save_spec == 0:

examples/PySDM_examples/Shipway_and_Hill_2012/fig_1.ipynb

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@
4444
" pip_install_on_colab('PySDM-examples')"
4545
]
4646
},
47+
{
48+
"cell_type": "code",
49+
"execution_count": 3,
50+
"metadata": {},
51+
"outputs": [],
52+
"source": [
53+
"import os"
54+
]
55+
},
4756
{
4857
"cell_type": "code",
4958
"execution_count": 2,
@@ -85,6 +94,9 @@
8594
" \"kappa\": .9,\n",
8695
" \"particles_per_volume_STP\": 50 / si.cm**3\n",
8796
"}\n",
97+
"if 'CI' in os.environ:\n",
98+
" common_params[\"t_max\"] = 10 * common_params[\"dt\"]\n",
99+
" common_params[\"n_sd_per_gridbox\"] = 16 \n",
88100
"\n",
89101
"output = {}\n",
90102
"settings = {}\n",
@@ -104,7 +116,7 @@
104116
" precip=precip\n",
105117
" )\n",
106118
" simulation[key] = Simulation(settings[key])\n",
107-
" output[key] = simulation[key].run().products\n"
119+
" output[key] = simulation[key].run().products"
108120
]
109121
},
110122
{
@@ -327,7 +339,7 @@
327339
],
328340
"metadata": {
329341
"kernelspec": {
330-
"display_name": "Python 3.9.4 ('edjPySDM')",
342+
"display_name": "Python 3 (ipykernel)",
331343
"language": "python",
332344
"name": "python3"
333345
},
@@ -341,7 +353,7 @@
341353
"name": "python",
342354
"nbconvert_exporter": "python",
343355
"pygments_lexer": "ipython3",
344-
"version": "3.9.4"
356+
"version": "3.9.2"
345357
},
346358
"vscode": {
347359
"interpreter": {
@@ -350,5 +362,5 @@
350362
}
351363
},
352364
"nbformat": 4,
353-
"nbformat_minor": 1
365+
"nbformat_minor": 4
354366
}

examples/PySDM_examples/Shipway_and_Hill_2012/simulation.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ def zZ_to_z_above_reservoir(zZ):
168168
PySDM_products.CoalescenceRatePerGridbox(
169169
name="coalescence_rate",
170170
),
171+
PySDM_products.SurfacePrecipitation(),
171172
]
172173
)
173174
self.particulator = self.builder.build(
@@ -182,7 +183,9 @@ def zZ_to_z_above_reservoir(zZ):
182183
}
183184
self.output_products = {}
184185
for k, v in self.particulator.products.items():
185-
if len(v.shape) == 1:
186+
if len(v.shape) == 0:
187+
self.output_products[k] = np.zeros(self.nt + 1)
188+
elif len(v.shape) == 1:
186189
self.output_products[k] = np.zeros((self.mesh.grid[-1], self.nt + 1))
187190
elif len(v.shape) == 2:
188191
number_of_time_sections = len(self.save_spec_and_attr_times)
@@ -203,7 +206,10 @@ def save_scalar(self, step):
203206
for k, v in self.particulator.products.items():
204207
if len(v.shape) > 1:
205208
continue
206-
self.output_products[k][:, step] = v.get()
209+
if len(v.shape) == 1:
210+
self.output_products[k][:, step] = v.get()
211+
else:
212+
self.output_products[k][step] = v.get()
207213

208214
def save_spectrum(self, index):
209215
for k, v in self.particulator.products.items():
Lines changed: 118 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# pylint: disable = missing-module-docstring,missing-class-docstring,missing-function-docstring
22
import os
33
import platform
4+
from collections import namedtuple
5+
from pathlib import Path
46
from tempfile import TemporaryDirectory
57

68
import numpy as np
@@ -20,127 +22,138 @@ def simulation_1d_fixture():
2022
n_sd_per_gridbox=n_sd_per_gridbox,
2123
dt=60 * si.s,
2224
dz=200 * si.m,
23-
precip=False,
25+
precip=True,
2426
rho_times_w_1=2 * si.m / si.s * si.kg / si.m**3,
2527
)
2628
settings.t_max = 20 * settings.dt
2729
settings.save_spec_and_attr_times = [0 * si.min, 10 * si.min, 20 * si.min]
2830
simulation = Simulation(settings)
2931
results = simulation.run()
30-
return results, settings, simulation
32+
return namedtuple(
33+
Path(__file__).stem + "_FixtureData", ("results, settings, simulation")
34+
)(results=results, settings=settings, simulation=simulation)
3135

3236

33-
@pytest.mark.parametrize(
34-
"exclude_particle_reservoir",
35-
(
36-
False,
37-
True,
38-
),
39-
)
40-
def test_netcdf_exporter_1d(simulation_1d, exclude_particle_reservoir):
41-
# Arrange
42-
data = simulation_1d[0].products
43-
settings = simulation_1d[1]
44-
simulation = simulation_1d[2]
45-
nz_export = (
46-
int(settings.z_max / settings.dz) if exclude_particle_reservoir else settings.nz
37+
class Test2DExporters:
38+
@staticmethod
39+
@pytest.mark.parametrize(
40+
"exclude_particle_reservoir",
41+
(
42+
False,
43+
True,
44+
),
4745
)
48-
49-
# Act
50-
file = TemporaryFile(".nc")
51-
netcdf_exporter = NetCDFExporter_1d(
52-
data,
53-
settings,
54-
simulation,
55-
filename=file.absolute_path,
56-
exclude_particle_reservoir=exclude_particle_reservoir,
57-
)
58-
netcdf_exporter.run()
59-
data_from_file = readNetCDF_1d(file.absolute_path)
60-
61-
# Assert
62-
assert data_from_file.products["time"].shape == data["t"].shape
63-
assert data_from_file.products["height"].shape == data["z"][-nz_export:].shape
64-
assert data_from_file.products["T"].shape == data["T"][-nz_export:, :].shape
65-
assert (
66-
data_from_file.products["dry spectrum"].shape
67-
== data["dry spectrum"][-nz_export:, :, :].shape
68-
)
69-
70-
assert np.amin(data_from_file.products["time"]) == np.amin(data["t"])
71-
assert np.amax(data_from_file.products["time"]) == np.amax(data["t"])
72-
assert np.amin(data_from_file.products["height"]) == np.amin(data["z"][-nz_export:])
73-
assert np.amax(data_from_file.products["height"]) == np.amax(data["z"][-nz_export:])
74-
assert data_from_file.products["rhod"].mean() == pytest.approx(
75-
data["rhod"][-nz_export:, :].mean(), 1e-6
76-
)
77-
assert data_from_file.products["wet spectrum"].mean() == pytest.approx(
78-
data["wet spectrum"][-nz_export:, :, :].mean(), 1e-6
79-
)
80-
81-
assert data_from_file.settings["precip"] == settings.precip
82-
assert data_from_file.settings["kappa"] == settings.kappa
83-
assert data_from_file.settings["r_bins_edges"].size == settings.number_of_bins + 1
84-
85-
86-
@pytest.mark.skipif(
87-
platform.architecture()[0] == "32bit", reason="Not available vtk module!"
88-
)
89-
@pytest.mark.parametrize(
90-
"exclude_particle_reservoir",
91-
(
92-
False,
93-
True,
94-
),
95-
)
96-
def test_vtk_exporter_1d(
97-
simulation_1d, exclude_particle_reservoir
98-
): # pylint: disable=too-many-locals
99-
# Arrange
100-
data = simulation_1d[0].attributes
101-
settings = simulation_1d[1]
102-
z0 = 0.0 if exclude_particle_reservoir else -settings.particle_reservoir_depth
103-
exported_particles_indexes = {}
104-
number_of_exported_particles = []
105-
for i, t in enumerate(settings.save_spec_and_attr_times):
106-
exported_particles_indexes[t] = np.where(
107-
data["cell origin"][i][0]
108-
>= int((z0 + settings.particle_reservoir_depth) / settings.dz)
46+
def test_netcdf_exporter_1d(simulation_1d, exclude_particle_reservoir):
47+
# Arrange
48+
data = simulation_1d.results.products
49+
settings = simulation_1d.settings
50+
nz_export = (
51+
int(settings.z_max / settings.dz)
52+
if exclude_particle_reservoir
53+
else settings.nz
10954
)
110-
number_of_exported_particles.append(exported_particles_indexes[t][0].size)
11155

112-
# Act
113-
with TemporaryDirectory() as tmpdir_:
114-
tmpdir = tmpdir_ + "/"
115-
vtk_exporter = VTKExporter_1d(
56+
# Act
57+
file = TemporaryFile(".nc")
58+
netcdf_exporter = NetCDFExporter_1d(
11659
data,
11760
settings,
118-
path=tmpdir,
61+
simulation_1d.simulation,
62+
filename=file.absolute_path,
11963
exclude_particle_reservoir=exclude_particle_reservoir,
12064
)
121-
vtk_exporter.run()
122-
written_files_list = os.listdir(tmpdir)
123-
data_from_file = {}
124-
for t in settings.save_spec_and_attr_times:
125-
leading_zeros_in_filename = [
126-
"0" for i in range(len(str(settings.t_max)) - len(str(t)))
127-
]
128-
filename = "time" + "".join(leading_zeros_in_filename) + str(t) + ".vtu"
129-
data_from_file[t] = readVTK_1d(tmpdir + filename)
65+
netcdf_exporter.run()
66+
data_from_file = readNetCDF_1d(file.absolute_path)
67+
68+
# Assert
69+
assert data_from_file.products["time"].shape == data["t"].shape
70+
assert data_from_file.products["height"].shape == data["z"][-nz_export:].shape
71+
assert data_from_file.products["T"].shape == data["T"][-nz_export:, :].shape
72+
assert (
73+
data_from_file.products["dry spectrum"].shape
74+
== data["dry spectrum"][-nz_export:, :, :].shape
75+
)
13076

131-
# Assert
132-
for i, t in enumerate(settings.save_spec_and_attr_times):
133-
filename_leading_zeros = "".join(
134-
["0" for i in range(len(str(settings.t_max)) - len(str(t)))]
77+
assert np.amin(data_from_file.products["time"]) == np.amin(data["t"])
78+
assert np.amax(data_from_file.products["time"]) == np.amax(data["t"])
79+
assert np.amin(data_from_file.products["height"]) == np.amin(
80+
data["z"][-nz_export:]
81+
)
82+
assert np.amax(data_from_file.products["height"]) == np.amax(
83+
data["z"][-nz_export:]
13584
)
136-
filename = "time" + filename_leading_zeros + str(t) + ".vtu"
137-
assert filename in written_files_list
138-
assert z0 <= np.amin(data_from_file[t]["z"])
139-
assert np.amax(data_from_file[t]["z"]) <= settings.z_max
140-
assert data_from_file[t]["z"].size == number_of_exported_particles[i]
141-
data_from_file[t].pop("z")
142-
assert data.keys() == data_from_file[t].keys()
85+
assert data_from_file.products["rhod"].mean() == pytest.approx(
86+
data["rhod"][-nz_export:, :].mean(), 1e-6
87+
)
88+
assert data_from_file.products["wet spectrum"].mean() == pytest.approx(
89+
data["wet spectrum"][-nz_export:, :, :].mean(), 1e-6
90+
)
91+
92+
assert data_from_file.settings["precip"] == settings.precip
93+
assert data_from_file.settings["kappa"] == settings.kappa
14394
assert (
144-
data["radius"][i][exported_particles_indexes[t]].mean()
145-
== data_from_file[t]["radius"].mean()
95+
data_from_file.settings["r_bins_edges"].size == settings.number_of_bins + 1
14696
)
97+
98+
@staticmethod
99+
@pytest.mark.skipif(
100+
platform.architecture()[0] == "32bit", reason="Not available vtk module!"
101+
)
102+
@pytest.mark.parametrize(
103+
"exclude_particle_reservoir",
104+
(
105+
False,
106+
True,
107+
),
108+
)
109+
def test_vtk_exporter_1d(
110+
simulation_1d, exclude_particle_reservoir
111+
): # pylint: disable=too-many-locals
112+
# Arrange
113+
data = simulation_1d.results.attributes
114+
settings = simulation_1d[1]
115+
z0 = 0.0 if exclude_particle_reservoir else -settings.particle_reservoir_depth
116+
exported_particles_indexes = {}
117+
number_of_exported_particles = []
118+
for i, t in enumerate(settings.save_spec_and_attr_times):
119+
exported_particles_indexes[t] = np.where(
120+
data["cell origin"][i][0]
121+
>= int((z0 + settings.particle_reservoir_depth) / settings.dz)
122+
)
123+
number_of_exported_particles.append(exported_particles_indexes[t][0].size)
124+
125+
# Act
126+
with TemporaryDirectory() as tmpdir_:
127+
tmpdir = tmpdir_ + "/"
128+
vtk_exporter = VTKExporter_1d(
129+
data,
130+
settings,
131+
path=tmpdir,
132+
exclude_particle_reservoir=exclude_particle_reservoir,
133+
)
134+
vtk_exporter.run()
135+
written_files_list = os.listdir(tmpdir)
136+
data_from_file = {}
137+
for t in settings.save_spec_and_attr_times:
138+
leading_zeros_in_filename = [
139+
"0" for i in range(len(str(settings.t_max)) - len(str(t)))
140+
]
141+
filename = "time" + "".join(leading_zeros_in_filename) + str(t) + ".vtu"
142+
data_from_file[t] = readVTK_1d(tmpdir + filename)
143+
144+
# Assert
145+
for i, t in enumerate(settings.save_spec_and_attr_times):
146+
filename_leading_zeros = "".join(
147+
["0" for i in range(len(str(settings.t_max)) - len(str(t)))]
148+
)
149+
filename = "time" + filename_leading_zeros + str(t) + ".vtu"
150+
assert filename in written_files_list
151+
assert z0 <= np.amin(data_from_file[t]["z"])
152+
assert np.amax(data_from_file[t]["z"]) <= settings.z_max
153+
assert data_from_file[t]["z"].size == number_of_exported_particles[i]
154+
data_from_file[t].pop("z")
155+
assert data.keys() == data_from_file[t].keys()
156+
assert (
157+
data["radius"][i][exported_particles_indexes[t]].mean()
158+
== data_from_file[t]["radius"].mean()
159+
)

tests/smoke_tests/kinematic_1d/shipway_and_hill_2012/test_few_steps.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def test_few_steps_no_precip(particle_reservoir_depth, plot=False):
2323
n_sd_per_gridbox=n_sd_per_gridbox,
2424
dt=30 * si.s,
2525
dz=60 * si.m,
26-
precip=False,
26+
precip=True,
2727
rho_times_w_1=2 * si.m / si.s * si.kg / si.m**3,
2828
)
2929
settings.particle_reservoir_depth = particle_reservoir_depth
@@ -80,6 +80,7 @@ def mean_profile_over_last_steps(var, smooth=True):
8080
assert max(mean_profile_over_last_steps("activating")) == 0
8181
assert max(mean_profile_over_last_steps("ripening")) > 0
8282
assert max(mean_profile_over_last_steps("deactivating")) > 0
83+
assert max(output["surface precipitation"]) == 0
8384

8485

8586
def test_fixed_thd():

0 commit comments

Comments
 (0)