modverif 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {modverif-0.2.2 → modverif-0.2.4}/PKG-INFO +1 -1
- {modverif-0.2.2 → modverif-0.2.4}/modverif/__init__.py +1 -1
- {modverif-0.2.2 → modverif-0.2.4}/modverif/composite.py +64 -41
- {modverif-0.2.2 → modverif-0.2.4}/.gitignore +0 -0
- {modverif-0.2.2 → modverif-0.2.4}/LICENSE +0 -0
- {modverif-0.2.2 → modverif-0.2.4}/README.md +0 -0
- {modverif-0.2.2 → modverif-0.2.4}/modverif/cyclone.py +0 -0
- {modverif-0.2.2 → modverif-0.2.4}/modverif/evaluate.py +0 -0
- {modverif-0.2.2 → modverif-0.2.4}/modverif/evaluator.py +0 -0
- {modverif-0.2.2 → modverif-0.2.4}/modverif/metrics.py +0 -0
- {modverif-0.2.2 → modverif-0.2.4}/modverif/plots.py +0 -0
- {modverif-0.2.2 → modverif-0.2.4}/modverif/station.py +0 -0
- {modverif-0.2.2 → modverif-0.2.4}/modverif/wrfio.py +0 -0
- {modverif-0.2.2 → modverif-0.2.4}/pyproject.toml +0 -0
|
@@ -68,7 +68,9 @@ def _read_grid_from_ds(ds):
|
|
|
68
68
|
Read 2D grid coordinate arrays and CRS info from a cfdb dataset.
|
|
69
69
|
|
|
70
70
|
For datasets with ``latitude``/``longitude``: returns lat/lon arrays,
|
|
71
|
-
data_crs=PlateCarree, is_projected=False.
|
|
71
|
+
data_crs=PlateCarree, is_projected=False. Longitudes > 180 are wrapped
|
|
72
|
+
to the -180..180 range and the longitude axis is reordered so values
|
|
73
|
+
are ascending (handles data that crosses the antimeridian).
|
|
72
74
|
|
|
73
75
|
For projected datasets with ``y``/``x`` and a CRS: returns native
|
|
74
76
|
projected coordinate arrays, the CRS, is_projected=True.
|
|
@@ -76,21 +78,35 @@ def _read_grid_from_ds(ds):
|
|
|
76
78
|
Returns
|
|
77
79
|
-------
|
|
78
80
|
tuple
|
|
79
|
-
(x2d, y2d, data_crs, is_projected) where x2d/y2d
|
|
80
|
-
in native coordinates
|
|
81
|
+
(x2d, y2d, data_crs, is_projected, lon_sort_idx) where x2d/y2d
|
|
82
|
+
are 2D arrays in native coordinates, data_crs is a pyproj.CRS,
|
|
83
|
+
and lon_sort_idx is an index array to reorder data along the
|
|
84
|
+
longitude axis (None if no reordering needed).
|
|
81
85
|
"""
|
|
82
86
|
coord_names = set(ds.coord_names)
|
|
83
87
|
var_names = set(ds.data_var_names)
|
|
84
88
|
|
|
85
89
|
if 'latitude' in coord_names or 'latitude' in var_names:
|
|
86
90
|
xlat, xlong = _read_latlon_2d(ds)
|
|
87
|
-
|
|
91
|
+
|
|
92
|
+
# Handle antimeridian: wrap > 180 and reorder so lons are ascending
|
|
93
|
+
lon_sort_idx = None
|
|
94
|
+
if np.any(xlong > 180):
|
|
95
|
+
xlong = np.where(xlong > 180, xlong - 360, xlong)
|
|
96
|
+
if xlong.ndim == 2:
|
|
97
|
+
# 1D coordinates meshed into 2D — reorder along lon axis
|
|
98
|
+
lon_1d = xlong[0, :]
|
|
99
|
+
lon_sort_idx = np.argsort(lon_1d)
|
|
100
|
+
xlong = xlong[:, lon_sort_idx]
|
|
101
|
+
xlat = xlat[:, lon_sort_idx]
|
|
102
|
+
|
|
103
|
+
return xlong, xlat, None, False, lon_sort_idx
|
|
88
104
|
|
|
89
105
|
if 'y' in coord_names and 'x' in coord_names and ds.crs is not None:
|
|
90
106
|
y_1d = ds['y'].data
|
|
91
107
|
x_1d = ds['x'].data
|
|
92
108
|
x2d, y2d = np.meshgrid(x_1d, y_1d)
|
|
93
|
-
return x2d, y2d, ds.crs, True
|
|
109
|
+
return x2d, y2d, ds.crs, True, None
|
|
94
110
|
|
|
95
111
|
raise ValueError(
|
|
96
112
|
"Dataset must contain either 'latitude'/'longitude' coordinates "
|
|
@@ -99,6 +115,13 @@ def _read_grid_from_ds(ds):
|
|
|
99
115
|
)
|
|
100
116
|
|
|
101
117
|
|
|
118
|
+
def _apply_lon_sort(data_2d, lon_sort_idx):
|
|
119
|
+
"""Reorder a 2D array along the longitude axis if needed."""
|
|
120
|
+
if lon_sort_idx is not None:
|
|
121
|
+
return data_2d[:, lon_sort_idx]
|
|
122
|
+
return data_2d
|
|
123
|
+
|
|
124
|
+
|
|
102
125
|
def _draw_composite_layers(
|
|
103
126
|
ax,
|
|
104
127
|
x2d: np.ndarray,
|
|
@@ -432,7 +455,7 @@ def plot_storm_composite_timestep(
|
|
|
432
455
|
raise FileNotFoundError(f"Dataset not found: {cfdb_path}")
|
|
433
456
|
|
|
434
457
|
with cfdb.open_dataset(cfdb_path) as ds:
|
|
435
|
-
x2d, y2d, data_crs, is_projected = _read_grid_from_ds(ds)
|
|
458
|
+
x2d, y2d, data_crs, is_projected, lon_sort = _read_grid_from_ds(ds)
|
|
436
459
|
time_values = ds['time'].data
|
|
437
460
|
|
|
438
461
|
# Validate time index
|
|
@@ -440,15 +463,15 @@ def plot_storm_composite_timestep(
|
|
|
440
463
|
raise IndexError(f"time_index {time_index} out of range [0, {len(time_values) - 1}]")
|
|
441
464
|
|
|
442
465
|
# Read fields
|
|
443
|
-
vimf_u = _read_var_2d(ds, vimf_u_var, time_index)
|
|
444
|
-
vimf_v = _read_var_2d(ds, vimf_v_var, time_index)
|
|
445
|
-
pwat = _read_var_2d(ds, pwat_var, time_index)
|
|
466
|
+
vimf_u = _apply_lon_sort(_read_var_2d(ds, vimf_u_var, time_index), lon_sort)
|
|
467
|
+
vimf_v = _apply_lon_sort(_read_var_2d(ds, vimf_v_var, time_index), lon_sort)
|
|
468
|
+
pwat = _apply_lon_sort(_read_var_2d(ds, pwat_var, time_index), lon_sort)
|
|
446
469
|
|
|
447
470
|
# MSLP with compute fallback
|
|
448
471
|
if mslp_var == 'mslp':
|
|
449
|
-
mslp = _read_slp_from_cfdb(ds, time_index)
|
|
472
|
+
mslp = _apply_lon_sort(_read_slp_from_cfdb(ds, time_index), lon_sort)
|
|
450
473
|
else:
|
|
451
|
-
mslp = _read_var_2d(ds, mslp_var, time_index)
|
|
474
|
+
mslp = _apply_lon_sort(_read_var_2d(ds, mslp_var, time_index), lon_sort)
|
|
452
475
|
|
|
453
476
|
time_str = str(time_values[time_index])
|
|
454
477
|
|
|
@@ -532,7 +555,7 @@ def plot_storm_composite(
|
|
|
532
555
|
png_files = []
|
|
533
556
|
|
|
534
557
|
with cfdb.open_dataset(cfdb_path) as ds:
|
|
535
|
-
x2d, y2d, data_crs, is_projected = _read_grid_from_ds(ds)
|
|
558
|
+
x2d, y2d, data_crs, is_projected, lon_sort = _read_grid_from_ds(ds)
|
|
536
559
|
time_values = ds['time'].data
|
|
537
560
|
n_times = len(time_values)
|
|
538
561
|
|
|
@@ -571,14 +594,14 @@ def plot_storm_composite(
|
|
|
571
594
|
continue
|
|
572
595
|
|
|
573
596
|
# Read fields
|
|
574
|
-
vimf_u = _read_var_2d(ds, vimf_u_var, t)
|
|
575
|
-
vimf_v = _read_var_2d(ds, vimf_v_var, t)
|
|
576
|
-
pwat = _read_var_2d(ds, pwat_var, t)
|
|
597
|
+
vimf_u = _apply_lon_sort(_read_var_2d(ds, vimf_u_var, t), lon_sort)
|
|
598
|
+
vimf_v = _apply_lon_sort(_read_var_2d(ds, vimf_v_var, t), lon_sort)
|
|
599
|
+
pwat = _apply_lon_sort(_read_var_2d(ds, pwat_var, t), lon_sort)
|
|
577
600
|
|
|
578
601
|
if mslp_var == 'mslp':
|
|
579
|
-
mslp = _read_slp_from_cfdb(ds, t)
|
|
602
|
+
mslp = _apply_lon_sort(_read_slp_from_cfdb(ds, t), lon_sort)
|
|
580
603
|
else:
|
|
581
|
-
mslp = _read_var_2d(ds, mslp_var, t)
|
|
604
|
+
mslp = _apply_lon_sort(_read_var_2d(ds, mslp_var, t), lon_sort)
|
|
582
605
|
|
|
583
606
|
time_str = str(t_val)
|
|
584
607
|
frame_path = output_dir / f'{filename_prefix}_t{t:03d}.png'
|
|
@@ -827,8 +850,8 @@ def plot_storm_composite_comparison_timestep(
|
|
|
827
850
|
raise FileNotFoundError(f"Dataset not found: {cfdb_path_b}")
|
|
828
851
|
|
|
829
852
|
with cfdb.open_dataset(cfdb_path_a) as ds_a, cfdb.open_dataset(cfdb_path_b) as ds_b:
|
|
830
|
-
x2d_a, y2d_a, data_crs_a, is_projected_a = _read_grid_from_ds(ds_a)
|
|
831
|
-
x2d_b, y2d_b, data_crs_b, is_projected_b = _read_grid_from_ds(ds_b)
|
|
853
|
+
x2d_a, y2d_a, data_crs_a, is_projected_a, lon_sort_a = _read_grid_from_ds(ds_a)
|
|
854
|
+
x2d_b, y2d_b, data_crs_b, is_projected_b, lon_sort_b = _read_grid_from_ds(ds_b)
|
|
832
855
|
|
|
833
856
|
times_a = ds_a['time'].data
|
|
834
857
|
times_b = ds_b['time'].data
|
|
@@ -842,22 +865,22 @@ def plot_storm_composite_comparison_timestep(
|
|
|
842
865
|
t_val, idx_a, idx_b = matched[time_index]
|
|
843
866
|
|
|
844
867
|
# Read fields from dataset A
|
|
845
|
-
vimf_u_a = _read_var_2d(ds_a, vimf_u_var_a, idx_a)
|
|
846
|
-
vimf_v_a = _read_var_2d(ds_a, vimf_v_var_a, idx_a)
|
|
847
|
-
pwat_a = _read_var_2d(ds_a, pwat_var_a, idx_a)
|
|
868
|
+
vimf_u_a = _apply_lon_sort(_read_var_2d(ds_a, vimf_u_var_a, idx_a), lon_sort_a)
|
|
869
|
+
vimf_v_a = _apply_lon_sort(_read_var_2d(ds_a, vimf_v_var_a, idx_a), lon_sort_a)
|
|
870
|
+
pwat_a = _apply_lon_sort(_read_var_2d(ds_a, pwat_var_a, idx_a), lon_sort_a)
|
|
848
871
|
if mslp_var_a == 'mslp':
|
|
849
|
-
mslp_a = _read_slp_from_cfdb(ds_a, idx_a)
|
|
872
|
+
mslp_a = _apply_lon_sort(_read_slp_from_cfdb(ds_a, idx_a), lon_sort_a)
|
|
850
873
|
else:
|
|
851
|
-
mslp_a = _read_var_2d(ds_a, mslp_var_a, idx_a)
|
|
874
|
+
mslp_a = _apply_lon_sort(_read_var_2d(ds_a, mslp_var_a, idx_a), lon_sort_a)
|
|
852
875
|
|
|
853
876
|
# Read fields from dataset B
|
|
854
|
-
vimf_u_b = _read_var_2d(ds_b, vimf_u_var_b, idx_b)
|
|
855
|
-
vimf_v_b = _read_var_2d(ds_b, vimf_v_var_b, idx_b)
|
|
856
|
-
pwat_b = _read_var_2d(ds_b, pwat_var_b, idx_b)
|
|
877
|
+
vimf_u_b = _apply_lon_sort(_read_var_2d(ds_b, vimf_u_var_b, idx_b), lon_sort_b)
|
|
878
|
+
vimf_v_b = _apply_lon_sort(_read_var_2d(ds_b, vimf_v_var_b, idx_b), lon_sort_b)
|
|
879
|
+
pwat_b = _apply_lon_sort(_read_var_2d(ds_b, pwat_var_b, idx_b), lon_sort_b)
|
|
857
880
|
if mslp_var_b == 'mslp':
|
|
858
|
-
mslp_b = _read_slp_from_cfdb(ds_b, idx_b)
|
|
881
|
+
mslp_b = _apply_lon_sort(_read_slp_from_cfdb(ds_b, idx_b), lon_sort_b)
|
|
859
882
|
else:
|
|
860
|
-
mslp_b = _read_var_2d(ds_b, mslp_var_b, idx_b)
|
|
883
|
+
mslp_b = _apply_lon_sort(_read_var_2d(ds_b, mslp_var_b, idx_b), lon_sort_b)
|
|
861
884
|
|
|
862
885
|
time_str = str(t_val)
|
|
863
886
|
|
|
@@ -960,8 +983,8 @@ def plot_storm_composite_comparison(
|
|
|
960
983
|
png_files = []
|
|
961
984
|
|
|
962
985
|
with cfdb.open_dataset(cfdb_path_a) as ds_a, cfdb.open_dataset(cfdb_path_b) as ds_b:
|
|
963
|
-
x2d_a, y2d_a, data_crs_a, is_projected_a = _read_grid_from_ds(ds_a)
|
|
964
|
-
x2d_b, y2d_b, data_crs_b, is_projected_b = _read_grid_from_ds(ds_b)
|
|
986
|
+
x2d_a, y2d_a, data_crs_a, is_projected_a, lon_sort_a = _read_grid_from_ds(ds_a)
|
|
987
|
+
x2d_b, y2d_b, data_crs_b, is_projected_b, lon_sort_b = _read_grid_from_ds(ds_b)
|
|
965
988
|
|
|
966
989
|
times_a = ds_a['time'].data
|
|
967
990
|
times_b = ds_b['time'].data
|
|
@@ -992,22 +1015,22 @@ def plot_storm_composite_comparison(
|
|
|
992
1015
|
|
|
993
1016
|
for i, (t_val, idx_a, idx_b) in enumerate(matched):
|
|
994
1017
|
# Read fields from dataset A
|
|
995
|
-
vimf_u_a = _read_var_2d(ds_a, vimf_u_var_a, idx_a)
|
|
996
|
-
vimf_v_a = _read_var_2d(ds_a, vimf_v_var_a, idx_a)
|
|
997
|
-
pwat_a = _read_var_2d(ds_a, pwat_var_a, idx_a)
|
|
1018
|
+
vimf_u_a = _apply_lon_sort(_read_var_2d(ds_a, vimf_u_var_a, idx_a), lon_sort_a)
|
|
1019
|
+
vimf_v_a = _apply_lon_sort(_read_var_2d(ds_a, vimf_v_var_a, idx_a), lon_sort_a)
|
|
1020
|
+
pwat_a = _apply_lon_sort(_read_var_2d(ds_a, pwat_var_a, idx_a), lon_sort_a)
|
|
998
1021
|
if mslp_var_a == 'mslp':
|
|
999
|
-
mslp_a = _read_slp_from_cfdb(ds_a, idx_a)
|
|
1022
|
+
mslp_a = _apply_lon_sort(_read_slp_from_cfdb(ds_a, idx_a), lon_sort_a)
|
|
1000
1023
|
else:
|
|
1001
|
-
mslp_a = _read_var_2d(ds_a, mslp_var_a, idx_a)
|
|
1024
|
+
mslp_a = _apply_lon_sort(_read_var_2d(ds_a, mslp_var_a, idx_a), lon_sort_a)
|
|
1002
1025
|
|
|
1003
1026
|
# Read fields from dataset B
|
|
1004
|
-
vimf_u_b = _read_var_2d(ds_b, vimf_u_var_b, idx_b)
|
|
1005
|
-
vimf_v_b = _read_var_2d(ds_b, vimf_v_var_b, idx_b)
|
|
1006
|
-
pwat_b = _read_var_2d(ds_b, pwat_var_b, idx_b)
|
|
1027
|
+
vimf_u_b = _apply_lon_sort(_read_var_2d(ds_b, vimf_u_var_b, idx_b), lon_sort_b)
|
|
1028
|
+
vimf_v_b = _apply_lon_sort(_read_var_2d(ds_b, vimf_v_var_b, idx_b), lon_sort_b)
|
|
1029
|
+
pwat_b = _apply_lon_sort(_read_var_2d(ds_b, pwat_var_b, idx_b), lon_sort_b)
|
|
1007
1030
|
if mslp_var_b == 'mslp':
|
|
1008
|
-
mslp_b = _read_slp_from_cfdb(ds_b, idx_b)
|
|
1031
|
+
mslp_b = _apply_lon_sort(_read_slp_from_cfdb(ds_b, idx_b), lon_sort_b)
|
|
1009
1032
|
else:
|
|
1010
|
-
mslp_b = _read_var_2d(ds_b, mslp_var_b, idx_b)
|
|
1033
|
+
mslp_b = _apply_lon_sort(_read_var_2d(ds_b, mslp_var_b, idx_b), lon_sort_b)
|
|
1011
1034
|
|
|
1012
1035
|
time_str = str(t_val)
|
|
1013
1036
|
frame_path = output_dir / f'{filename_prefix}_t{i:03d}.png'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|