Skip to content

Commit ba5fc35

Browse files
author
radarv
committed
Merge branch 'dev'
2 parents b0d8aed + ff18d79 commit ba5fc35

File tree

15 files changed

+525
-109
lines changed

15 files changed

+525
-109
lines changed

doc/source/overview/index.rst

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,63 @@
11
Pyrad configuration files
22
==============================
33

4+
.. role:: red
5+
46
The configuration of the data processing in pyrad is divided into three files. The main configuration file, the location configuration file describing the location of the
57
weather radar and the used scans. Finally, the product configuration file describes the datasets and
68
products.
79

10+
Two formats are accepted for configuration files. The classical pyrad format which uses the following syntax::
11+
12+
ppiMapImageConfig STRUCT 12
13+
mapres STRING 10m
14+
alpha FLOAT 0.4
15+
latmin FLOAT 46.5
16+
latmax FLOAT 47.1
17+
lonmin FLOAT 6.5
18+
lonmax FLOAT 7.5
19+
lonstep FLOAT 0.1
20+
latstep FLOAT 0.1
21+
xsize FLOAT 18.
22+
ysize FLOAT 10.
23+
background_zoom INT 10
24+
maps STRARR 2 # maps to overplot (cartopy)
25+
OTM
26+
rivers
27+
28+
**Supported Data Types**
29+
30+
Scalar types:
31+
32+
* BYTE, INT, LONG, HEX: interpreted as integers (HEX supports 0x notation).
33+
* FLOAT, DOUBLE, EXP: interpreted as floating-point numbers.
34+
* BOOL: accepts true/1 (case-insensitive) → True, others → False.
35+
* STRING: interpreted as a string.
36+
37+
Array types:
38+
39+
* BYTARR, INTARR, LONARR, HEXARR: interpreted as a list of integers
40+
* FLTARR, DBLAR: EXPARR: interpreted as a list of floating-point numbers.
41+
* STRARR: interpreted as a list of strings.
42+
43+
44+
Every entry has three elements:
45+
46+
* *fieldname*: indentifier for the field
47+
* *TYPE*: one of the supported scalar or array types
48+
* *value* (for scalar types) or *number of elements* (for STRUCT or arrays)
49+
50+
**The number of elements must be correct or the processing will fail**
51+
52+
53+
54+
:red:`Since v2.1.0 of pyrad, you can also write your config files in the YAML format.`
55+
A `converter script <https://github.com/MeteoSwiss/pyrad/blob/master/src/pyrad_proc/scripts/config_to_yaml.py>`_
56+
is also available to convert your pyrad-style config files to YAML.
857

958
.. toctree::
1059
:maxdepth: 1
1160

1261
main
1362
loc
14-
prod
63+
prod

doc/source/overview/main.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ Table 2: Configuration parameters of the main configuration file
2323
``<datapath>/<scanname>/<YYYY-MM-DD>/<YYYYMMDDHHMMSS00datatype>.<ext>``
2424
* - configpath
2525
- STRING
26-
- Absolute base directory of the configuration files. This directory contains clutter maps, filter coefficients, antenna pattern, and the data processing configuration files. If any path within a pyrad config file is provided as a relative path, it will be converted to an absolute path, by prepending it with the path specified with "configpath".
26+
- Absolute base directory of the configuration files. This directory contains clutter maps, filter coefficients, antenna pattern, and the data processing configuration files. If any path within a pyrad config file is provided as a relative path, it will be converted to an absolute path, by prepending it with the path specified with "configpath". If not provided, the directory of the main config file will be used.
2727
* - locationConfigFile
2828
- STRING
29-
- File name (with full path) of the location configuration file. Described in Section 3.2.
29+
- File nameof the location configuration file. If only the filename (and not directory) is provided it will be prepended with configpath. Described in Section 3.2.
3030
* - productConfigFile
3131
- STRING
32-
- File name (with full path) of the product configuration file. Described in Section 4.
32+
- File name of the product configuration file. If only the filename (and not directory) is provided it will be prepended with configpath. Described in Section 4.
3333
* - lastStateFile
3434
- STRING
3535
- File name (with full path) of the file containing the time of the last processed scan. Used in particular for real-time processing.

src/pyart

src/pyrad_proc/pyrad/graph/plots.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,8 @@ def plot_scatter(
534534
rad2_name="RADAR002",
535535
titl="colocated radar gates",
536536
cmap=None,
537+
vmin=None,
538+
vmax=None,
537539
):
538540
"""
539541
2D histogram
@@ -563,6 +565,10 @@ def plot_scatter(
563565
cmap : str or None
564566
name of the colormap. If None it will be choosen the default for the
565567
field_name
568+
vmin: float
569+
Minimum value of the 2D histogram.
570+
vmax: float
571+
Maximum value of the 2D histogram.
566572
567573
Returns
568574
-------
@@ -616,6 +622,10 @@ def plot_scatter(
616622
ax.set_ylabel(labely)
617623
ax.set_title(titl)
618624

625+
if vmin and vmax:
626+
ax.set_xlim([vmin, vmax])
627+
ax.set_ylim([vmin, vmax])
628+
619629
cb = fig.colorbar(cax)
620630
cb.set_label(label)
621631

src/pyrad_proc/pyrad/io/io_aux.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3879,7 +3879,9 @@ def _get_datetime(fname, datagroup, ftime_format=None):
38793879
if ftime_format is None:
38803880
# we assume is rad4alp format
38813881
datetimestr = bfile[3:12]
3882-
fdatetime = datetime.datetime.strptime(datetimestr, "%y%j%H%M")
3882+
fdatetime = datetime.datetime.strptime(datetimestr, "%y%j%H%M").replace(
3883+
tzinfo=datetime.timezone.utc
3884+
)
38833885
else:
38843886
return find_date_in_file_name(
38853887
bfile, date_format=ftime_format[ftime_format.find("F") + 2 : -1]

src/pyrad_proc/pyrad/io/read_data_iso0_mf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,8 +385,8 @@ def read_iso0_grib_data(fname):
385385
for grb in grbs:
386386
lats, lons = grb.latlons()
387387
values.append(grb.values)
388-
date_analysis = grb.analDate
389-
date_fcst.append(grb.analDate + datetime.timedelta(hours=grb["startStep"]))
388+
date_analysis = grb.analDate.replace(tzinfo=datetime.timezone.utc)
389+
date_fcst.append(date_analysis + datetime.timedelta(hours=grb["startStep"]))
390390

391391
grbs.close()
392392

src/pyrad_proc/pyrad/io/read_data_radar.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1442,6 +1442,15 @@ def get_data(voltime, datatypesdescr, cfg):
14421442
radar.radar_calibration["dBADU_to_dBm_vv"]["data"][0] = cfg["dBADUtodBmv"][
14431443
ind_rad
14441444
]
1445+
1446+
# If radar name is empty substitude the one from the config file
1447+
if not radar.metadata.get("instrument_name"):
1448+
if "RadarName" in cfg:
1449+
try:
1450+
radar.metadata["instrument_name"] = cfg["RadarName"][ind_rad]
1451+
except (IndexError, TypeError):
1452+
pass
1453+
14451454
return radar
14461455

14471456

@@ -1993,7 +2002,6 @@ def merge_scans_odim(
19932002
azmin = cfg["azmin"][ind_rad]
19942003
if cfg["azmax"] is not None:
19952004
azmax = cfg["azmax"][ind_rad]
1996-
19972005
return pyart.util.subset_radar(
19982006
radar,
19992007
radar.fields.keys(),

src/pyrad_proc/pyrad/io/read_data_sensor.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2593,7 +2593,7 @@ def read_radiosounding_igra(station, dtime):
25932593
Please see this link for a description of the columns
25942594
https://www.ncei.noaa.gov/data/integrated-global-radiosonde-archive/doc/igra2-data-format.txt
25952595
"""
2596-
warn("Downloading sounding from IGRA database...")
2596+
print("Downloading sounding from IGRA database...")
25972597

25982598
COLUMNS_SOUNDING = [
25992599
"LVLTYPE1",
@@ -2649,7 +2649,9 @@ def read_radiosounding_igra(station, dtime):
26492649
return
26502650

26512651
# get igra code
2652-
code = stations_ref["CODE"][stations_ref["CODE"].str.contains(station)].iloc[0]
2652+
code = stations_ref["CODE"][
2653+
stations_ref["CODE"].str.contains(station, na=False)
2654+
].iloc[0]
26532655

26542656
# Check if specified time is after 2021
26552657
if dtime > datetime.datetime(2021, 1, 1):
@@ -2702,8 +2704,8 @@ def read_radiosounding_igra(station, dtime):
27022704
line_start = line_starts[idx_clo]
27032705

27042706
if not line_start:
2705-
warn(
2706-
"Could not find a sounding in the IGRA database that corresponds to prescribed time"
2707+
print(
2708+
"Could not find a sounding in the IGRA database that corresponds to prescribed time",
27072709
)
27082710

27092711
file_content = file_content[line_start + 1 :]

src/pyrad_proc/pyrad/proc/process_aux.py

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -826,13 +826,13 @@ def process_vol_to_grid(procstatus, dscfg, radar_list=None):
826826
"data"
827827
][0]
828828
else:
829-
warn("beamwidth not defined. Assumed 1 deg")
829+
warn("beamwidth not defined. Assumed 1 deg", use_debug=False)
830830
beamwidth = 1.0
831831

832832
if radar_list_aux[0].ray_angle_res is not None:
833833
beam_spacing = radar_list_aux[0].ray_angle_res["data"][0]
834834
else:
835-
warn("beam spacing not defined. Assumed 1 deg")
835+
warn("beam spacing not defined. Assumed 1 deg", use_debug=False)
836836
beam_spacing = 1.0
837837

838838
# cartesian mapping
@@ -1193,7 +1193,10 @@ def process_keep_roi(procstatus, dscfg, radar_list=None):
11931193
res_cercle = dscfg.get("res_cercle", 16)
11941194

11951195
if lon_centre is None or lat_centre is None:
1196-
warn("cercle position undefined. " "The radar position will be used")
1196+
warn(
1197+
"cercle position undefined. " "The radar position will be used",
1198+
use_debug=False,
1199+
)
11971200
lon_centre = radar.longitude["data"][0]
11981201
lat_centre = radar.latitude["data"][0]
11991202

@@ -1223,7 +1226,10 @@ def process_keep_roi(procstatus, dscfg, radar_list=None):
12231226
sn_length = dscfg.get("sn_length", 1000.0) # m
12241227

12251228
if lon_point is None or lat_point is None:
1226-
warn("box position undefined. " "The radar position will be used")
1229+
warn(
1230+
"box position undefined. " "The radar position will be used",
1231+
use_debug=False,
1232+
)
12271233
lon_point = radar.longitude["data"][0]
12281234
lat_point = radar.latitude["data"][0]
12291235

@@ -1489,7 +1495,10 @@ def process_roi(procstatus, dscfg, radar_list=None):
14891495
res_cercle = dscfg.get("res_cercle", 16)
14901496

14911497
if lon_centre is None or lat_centre is None:
1492-
warn("cercle position undefined. " "The radar position will be used")
1498+
warn(
1499+
"cercle position undefined. " "The radar position will be used",
1500+
use_debug=False,
1501+
)
14931502
lon_centre = radar.longitude["data"][0]
14941503
lat_centre = radar.latitude["data"][0]
14951504

@@ -1519,7 +1528,10 @@ def process_roi(procstatus, dscfg, radar_list=None):
15191528
sn_length = dscfg.get("sn_length", 1000.0) # m
15201529

15211530
if lon_point is None or lat_point is None:
1522-
warn("box position undefined. " "The radar position will be used")
1531+
warn(
1532+
"box position undefined. " "The radar position will be used",
1533+
use_debug=False,
1534+
)
15231535
lon_point = radar.longitude["data"][0]
15241536
lat_point = radar.latitude["data"][0]
15251537

@@ -1768,7 +1780,10 @@ def process_roi2(procstatus, dscfg, radar_list=None):
17681780
nfields_available = 0
17691781
for field_name in field_names_aux:
17701782
if field_name not in radar.fields:
1771-
warn("Field name " + field_name + " not available in radar object")
1783+
warn(
1784+
"Field name " + field_name + " not available in radar object",
1785+
use_debug=False,
1786+
)
17721787
continue
17731788
field_names.append(field_name)
17741789
nfields_available += 1
@@ -1835,7 +1850,10 @@ def process_roi2(procstatus, dscfg, radar_list=None):
18351850
res_cercle = dscfg.get("res_cercle", 16)
18361851

18371852
if lon_centre is None or lat_centre is None:
1838-
warn("cercle position undefined. " "The radar position will be used")
1853+
warn(
1854+
"cercle position undefined. " "The radar position will be used",
1855+
use_debug=False,
1856+
)
18391857
lon_centre = radar.longitude["data"][0]
18401858
lat_centre = radar.latitude["data"][0]
18411859

@@ -1865,7 +1883,10 @@ def process_roi2(procstatus, dscfg, radar_list=None):
18651883
sn_length = dscfg.get("sn_length", 1000.0) # m
18661884

18671885
if lon_point is None or lat_point is None:
1868-
warn("box position undefined. " "The radar position will be used")
1886+
warn(
1887+
"box position undefined. " "The radar position will be used",
1888+
use_debug=False,
1889+
)
18691890
lon_point = radar.longitude["data"][0]
18701891
lat_point = radar.latitude["data"][0]
18711892

@@ -2105,7 +2126,10 @@ def process_azimuthal_average(procstatus, dscfg, radar_list=None):
21052126
nfields_available = 0
21062127
for field_name, datatype in zip(field_names_aux, datatypes_aux):
21072128
if field_name not in radar.fields:
2108-
warn("Field name " + field_name + " not available in radar object")
2129+
warn(
2130+
"Field name " + field_name + " not available in radar object",
2131+
use_debug=False,
2132+
)
21092133
continue
21102134
field_names.append(field_name)
21112135
datatypes.append(datatype)
@@ -2118,7 +2142,10 @@ def process_azimuthal_average(procstatus, dscfg, radar_list=None):
21182142
if datatype in dscfg["lin_trans"]:
21192143
lin_trans[field_name] = dscfg["lin_trans"] != 0
21202144
else:
2121-
warn("Averaging in linear units for {} not specified".format(datatype))
2145+
warn(
2146+
"Averaging in linear units for {} not specified".format(datatype),
2147+
use_debug=False,
2148+
)
21222149

21232150
if nfields_available == 0:
21242151
warn("Fields not available in radar data")
@@ -2412,7 +2439,8 @@ def process_radar_resampling(procstatus, dscfg, radar_list=None):
24122439
radar_antenna_atsameplace = True
24132440
warn(
24142441
"No target radar position specified. "
2415-
+ "The radars are assumed co-located"
2442+
+ "The radars are assumed co-located",
2443+
use_debug=False,
24162444
)
24172445
else:
24182446
radar_antenna_atsameplace = False
@@ -2569,7 +2597,8 @@ def process_radar_resampling(procstatus, dscfg, radar_list=None):
25692597
warn(
25702598
"Units type for data type "
25712599
+ datatype
2572-
+ " not specified. Assumed linear"
2600+
+ " not specified. Assumed linear",
2601+
use_debug=False,
25732602
)
25742603

25752604
use_nans.update({field_name: False})
@@ -2580,7 +2609,8 @@ def process_radar_resampling(procstatus, dscfg, radar_list=None):
25802609
warn(
25812610
"Use of nans not specified for data type "
25822611
+ datatype
2583-
+ " not specified. Assumed not used"
2612+
+ " not specified. Assumed not used",
2613+
use_debug=False,
25842614
)
25852615

25862616
nan_value.update({field_name: 0.0})
@@ -2591,7 +2621,8 @@ def process_radar_resampling(procstatus, dscfg, radar_list=None):
25912621
warn(
25922622
"NaN value not specified for data type "
25932623
+ datatype
2594-
+ " not specified. Assumed 0"
2624+
+ " not specified. Assumed 0",
2625+
use_debug=False,
25952626
)
25962627

25972628
# Persistent data structure

src/pyrad_proc/pyrad/proc/process_echoclass.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,10 @@ def process_hydroclass(procstatus, dscfg, radar_list=None):
14741474
weights : array of floats. Dataset keyword
14751475
Used with HYDRO_METHOD SEMISUPERVISED. The list of weights given
14761476
to each variable
1477+
frequency : float. Dataset keyword
1478+
the radar frequency [Hz]. If None that of the key
1479+
frequency in attribute instrument_parameters of the radar
1480+
object will be used.
14771481
hydropath : string. Dataset keyword
14781482
Used with HYDRO_METHOD UKMO. Directory of the UK MetOffice
14791483
hydrometeor classification code
@@ -1576,8 +1580,10 @@ def process_hydroclass(procstatus, dscfg, radar_list=None):
15761580
if "fzl" in dscfg:
15771581
freezing_level = dscfg["fzl"]
15781582
elif "sounding" in dscfg:
1579-
warn("No iso0 or temperature fields were provided")
1580-
warn("Getting freezing level height from sounding")
1583+
warn(
1584+
"No iso0 or temperature fields were provided, getting freezing level height from sounding",
1585+
use_debug=False,
1586+
)
15811587
sounding_code = dscfg["sounding"]
15821588
t0 = pyart.util.datetime_utils.datetime_from_radar(radar)
15831589
freezing_level = read_fzl_igra(sounding_code, t0, dscfg=dscfg)
@@ -1634,6 +1640,7 @@ def process_hydroclass(procstatus, dscfg, radar_list=None):
16341640
output_distances = dscfg.get("output_distances", False)
16351641
vectorize = dscfg.get("vectorize", False)
16361642
weights = dscfg.get("weights", np.array((1.0, 1.0, 1.0, 0.75, 0.5)))
1643+
freq = dscfg.get("frequency", None)
16371644

16381645
# load centroids
16391646
if centroids_file is not None:
@@ -1668,6 +1675,7 @@ def process_hydroclass(procstatus, dscfg, radar_list=None):
16681675
hydro_field=None,
16691676
entropy_field=None,
16701677
temp_ref=temp_ref,
1678+
radar_freq=freq,
16711679
compute_entropy=compute_entropy,
16721680
output_distances=output_distances,
16731681
vectorize=vectorize,

0 commit comments

Comments
 (0)