Skip to content

Commit ac777f6

Browse files
committed
Store analysis in verif files
1 parent f8f5631 commit ac777f6

2 files changed

Lines changed: 32 additions & 4 deletions

File tree

bris/outputs/verif.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,13 @@ def finalize(self) -> None:
225225
frts = self.intermediate.get_forecast_reference_times()
226226
frts_unix = utils.datetime_to_unixtime(frts).astype(np.double)
227227

228+
leadtimes_seconds = self.intermediate.pm.leadtimes.astype(np.float32)
229+
228230
coords = {}
229231
coords["time"] = (["time"], frts_unix, cf.get_attributes("time"))
230232
coords["leadtime"] = (
231233
["leadtime"],
232-
self.intermediate.pm.leadtimes.astype(np.float32) / 3600,
234+
leadtimes_seconds / 3600,
233235
{"units": "hour"},
234236
)
235237
assert len(self.obs_ids) == len(self.opoints.get_lats()), (
@@ -345,15 +347,14 @@ def finalize(self) -> None:
345347
self.ds["x"] = (["time", "leadtime", "location", "quantile"], x)
346348

347349
# Find which valid times we need observations for
348-
frts_ut = utils.datetime_to_unixtime(frts)
349-
a, b = np.meshgrid(frts_ut, np.array(self.intermediate.pm.leadtimes))
350+
# Build a 2D array of valid times for (init_time, leadtime)
351+
a, b = np.meshgrid(frts_unix, np.array(self.intermediate.pm.leadtimes))
350352
valid_times = a + b
351353
valid_times = valid_times.transpose()
352354
if len(valid_times) == 0:
353355
utils.LOGGER.warning("Could not finalize verif, no valid times")
354356
return
355357

356-
# valid_times = np.sort(np.unique(valid_times.flatten()))
357358
unique_valid_times = np.sort(np.unique(valid_times.flatten()))
358359

359360
start_time = int(np.min(unique_valid_times))
@@ -387,6 +388,21 @@ def finalize(self) -> None:
387388

388389
self.ds["obs"] = (["time", "leadtime", "location"], obs)
389390

391+
if int(leadtimes_seconds[0]) == 0:
392+
# Store the analysis state from "fcst", where it is available. Note: this picks the first
393+
# forecast leadtime, which isn't necesssarily going to be an analysis.
394+
analysis = self.create_nan_array(fcst_shape)
395+
analysis_valid_times = frts_unix
396+
397+
for _t, valid_time in enumerate(frts_unix):
398+
Itimes, Ileadtimes = np.where(valid_times == valid_time)
399+
for i in range(len(Itimes)):
400+
analysis[Itimes[i], Ileadtimes[i], :] = fcst[_t, 0, :]
401+
402+
self.ds["analysis"] = (["time", "leadtime", "location"], analysis)
403+
else:
404+
print("Not writing analysis to verif file. The first forecast leadtime isn't 0")
405+
390406
if self.num_members > 1:
391407
crps = self.compute_crps(ens, obs, self.fair_crps)
392408
self.ds["ensemble_crps"] = (["time", "leadtime", "location"], crps)
@@ -399,6 +415,7 @@ def finalize(self) -> None:
399415

400416
data_variables = [
401417
"obs",
418+
"analysis",
402419
"fcst",
403420
"ensemble",
404421
"ensemble_mean",

tests/test_outputs_verif.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import numpy as np
55
import pytest
6+
import xarray as xr
67

78
from bris.outputs import Verif
89
from bris.predict_metadata import PredictMetadata
@@ -64,6 +65,7 @@ def test_1():
6465
output.add_forecast(times, member, pred)
6566

6667
output.finalize()
68+
check_expected_variable(ofilename)
6769

6870
altitudes = np.arange(len(lats))
6971
pm = PredictMetadata(
@@ -90,6 +92,15 @@ def test_1():
9092
output.add_forecast(times, member, pred)
9193

9294
output.finalize()
95+
check_expected_variable(ofilename)
96+
97+
def check_expected_variable(filename):
98+
expected_variables = ["analysis", "fcst", "obs", "ensemble", "ensemble_mean",
99+
"ensemble_variance", "ensemble_crps"]
100+
101+
with xr.open_dataset(filename) as file:
102+
for variable in expected_variables:
103+
assert variable in file, variable
93104

94105

95106
def test_2():

0 commit comments

Comments
 (0)