Skip to content

Commit 36f74e5

Browse files
authored
Fix pymatrix fortran leak bug, add diameter_min option, improve L2M parameters defaults (#244)
* Improve L2M GS defaults * Fix doc typos * Fix pytmatrix bug and add diameter_min argument * Fix L0C bug when missing time block * Improve DWD reader and add pytmatrix missing tests * Improve test coverage * Fix test
1 parent fde7687 commit 36f74e5

29 files changed

Lines changed: 700 additions & 163 deletions

File tree

disdrodb/api/checks.py

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,64 @@ def check_scattering_table_dir(scattering_table_dir: str):
119119

120120

121121
def check_measurement_interval(measurement_interval):
122-
"""Check measurement interval validity."""
122+
"""Check measurement interval validity.
123+
124+
The measurement interval must be a positive natural number.
125+
It can be specified as an int or a float (but must represent a whole number)
126+
127+
Parameters
128+
----------
129+
measurement_interval : int or float
130+
The measurement interval value to validate.
131+
132+
Returns
133+
-------
134+
int
135+
The validated measurement interval as an integer.
136+
137+
Raises
138+
------
139+
ValueError
140+
If the measurement interval is not a valid positive natural number.
141+
TypeError
142+
If the measurement interval has an invalid type.
143+
"""
144+
# Check for None
145+
if measurement_interval is None:
146+
raise ValueError("'measurement_interval' cannot be None.")
147+
148+
# Check for empty string
123149
if isinstance(measurement_interval, str) and measurement_interval == "":
124-
raise ValueError("measurement_interval' must be specified as an integer value.")
125-
if isinstance(measurement_interval, type(None)):
126-
raise ValueError("measurement_interval' can not be None.")
127-
if isinstance(measurement_interval, str) and not measurement_interval.isdigit():
128-
raise ValueError("measurement_interval' is not a positive digit.")
129-
return int(measurement_interval)
150+
raise ValueError("'measurement_interval' must be specified as an integer value.")
151+
152+
# Check for boolean (bool is subclass of int, so check before int)
153+
if isinstance(measurement_interval, bool):
154+
raise TypeError("'measurement_interval' cannot be a boolean.")
155+
156+
# Handle string input
157+
if isinstance(measurement_interval, str):
158+
if not measurement_interval.isdigit():
159+
raise ValueError("'measurement_interval' is not a positive integer.")
160+
raise ValueError("'measurement_interval' must be specified as number, not as string'")
161+
162+
# Handle numeric input (int or float)
163+
if isinstance(measurement_interval, (int, float)):
164+
# Check if positive
165+
if measurement_interval <= 0:
166+
raise ValueError("'measurement_interval' must be a positive number.")
167+
168+
# Check if it's a whole number (no decimals)
169+
if measurement_interval != int(measurement_interval):
170+
raise ValueError(
171+
f"'measurement_interval' must be a natural number without decimals. Got {measurement_interval}.",
172+
)
173+
174+
return int(measurement_interval)
175+
176+
# Invalid type
177+
raise TypeError(
178+
f"'measurement_interval' must be an int or float. Got {type(measurement_interval).__name__}.",
179+
)
130180

131181

132182
def check_measurement_intervals(measurement_intervals):
@@ -611,7 +661,7 @@ def check_time(time):
611661
if isinstance(time, np.ndarray):
612662
if np.issubdtype(time.dtype, np.datetime64):
613663
if time.size == 1:
614-
time = time[0].astype("datetime64[s]").tolist()
664+
time = np.atleast_1d(time)[0].astype("datetime64[s]").tolist()
615665
else:
616666
raise ValueError("Expecting a single timestep!")
617667
else:

disdrodb/api/io.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,11 @@ def preprocess(ds):
570570
# Subset time
571571
if start_time is not None or end_time is not None:
572572
ds = filter_dataset_by_time(ds, start_time=start_time, end_time=end_time)
573-
573+
# Close connection and raise error if no timesteps available
574+
if ds.sizes["time"] == 0:
575+
ds.close()
576+
del ds
577+
raise ValueError(f"No timesteps available between {start_time} and {end_time}")
574578
# Ensure coordinates are already loaded in memory
575579
for coord in list(ds.coords):
576580
ds[coord] = ds[coord].load()

disdrodb/cli/pytmatrix_lut.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import os
2+
3+
import click
4+
5+
from disdrodb.scattering.routines import calculate_scatterer
6+
7+
8+
@click.command(context_settings={"help_option_names": ["-h", "--help"]})
9+
@click.option("--frequency", type=float, required=True, help="Radar frequency [GHz]")
10+
@click.option("--num-points", type=int, default=1024, show_default=True)
11+
@click.option("--diameter-min", type=float, default=0, show_default=True, help="Min diameter [mm]")
12+
@click.option("--diameter-max", type=float, default=8.0, show_default=True, help="Max diameter [mm]")
13+
@click.option("--canting-angle-std", type=float, default=7.0, show_default=True, help="Canting angle std [deg]")
14+
@click.option("--axis-ratio-model", type=str, default="Thurai2007", show_default=True)
15+
@click.option("--permittivity-model", type=str, default="Turner2016", show_default=True)
16+
@click.option("--water-temperature", type=float, default=10.0, show_default=True, help="Water temperature [°C]")
17+
@click.option("--elevation-angle", type=float, default=0.0, show_default=True)
18+
@click.argument("output", type=click.Path(dir_okay=False))
19+
def main(
20+
frequency,
21+
num_points,
22+
diameter_min,
23+
diameter_max,
24+
canting_angle_std,
25+
axis_ratio_model,
26+
permittivity_model,
27+
water_temperature,
28+
elevation_angle,
29+
output,
30+
):
31+
"""
32+
Compute ONE pyTMatrix scattering LUT in a fresh Python process.
33+
34+
OUTPUT is the full path to the .pkl LUT file.
35+
"""
36+
click.echo("Initializing pyTMatrix LUT generation...")
37+
38+
scatterer = calculate_scatterer(
39+
frequency=frequency,
40+
num_points=num_points,
41+
diameter_min=diameter_min,
42+
diameter_max=diameter_max,
43+
canting_angle_std=canting_angle_std,
44+
axis_ratio_model=axis_ratio_model,
45+
water_temperature=water_temperature,
46+
permittivity_model=permittivity_model,
47+
elevation_angle=elevation_angle,
48+
)
49+
50+
os.makedirs(os.path.dirname(output), exist_ok=True)
51+
scatterer.psd_integrator.save_scatter_table(output)
52+
53+
click.echo(f"✔ LUT written to {output}")

disdrodb/etc/products/L2E/LPM/global.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ radar_enabled: False
2828
radar_options:
2929
frequency: ["S", "C", "X", "Ku", "K", "Ka", "W"]
3030
num_points: 1024
31+
diameter_min: 0
3132
diameter_max: 10
3233
canting_angle_std: 7
3334
axis_ratio_model: Thurai2007

disdrodb/etc/products/L2E/LPM_V0/global.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ radar_enabled: False
2828
radar_options:
2929
frequency: ["S", "C", "X", "Ku", "K", "Ka", "W"]
3030
num_points: 1024
31+
diameter_min: 0
3132
diameter_max: 10
3233
canting_angle_std: 7
3334
axis_ratio_model: Thurai2007

disdrodb/etc/products/L2E/ODM470/global.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ radar_enabled: False
2828
radar_options:
2929
frequency: ["S", "C", "X", "Ku", "K", "Ka", "W"]
3030
num_points: 1024
31+
diameter_min: 0
3132
diameter_max: 10
3233
canting_angle_std: 7
3334
axis_ratio_model: Thurai2007

disdrodb/etc/products/L2E/PARSIVEL/global.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ radar_enabled: False
2828
radar_options:
2929
frequency: ["S", "C", "X", "Ku", "K", "Ka", "W"]
3030
num_points: 1024
31+
diameter_min: 0
3132
diameter_max: 10
3233
canting_angle_std: 7
3334
axis_ratio_model: Thurai2007

disdrodb/etc/products/L2E/PARSIVEL2/global.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ radar_enabled: False
2828
radar_options:
2929
frequency: ["S", "C", "X", "Ku", "K", "Ka", "W"]
3030
num_points: 1024
31+
diameter_min: 0
3132
diameter_max: 10
3233
canting_angle_std: 7
3334
axis_ratio_model: Thurai2007

disdrodb/etc/products/L2E/PWS100/global.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ radar_enabled: False
2828
radar_options:
2929
frequency: ["S", "C", "X", "Ku", "K", "Ka", "W"]
3030
num_points: 1024
31+
diameter_min: 0
3132
diameter_max: 10
3233
canting_angle_std: 7
3334
axis_ratio_model: Thurai2007

disdrodb/etc/products/L2E/global.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ radar_enabled: False
2828
radar_options:
2929
frequency: ["S", "C", "X", "Ku", "K", "Ka", "W"]
3030
num_points: 1024
31+
diameter_min: 0
3132
diameter_max: 10
3233
canting_angle_std: 7
3334
axis_ratio_model: Thurai2007

0 commit comments

Comments
 (0)