Repository navigation
Forecast capping if calibrate forecast is too far from the uncalibrated - #2449
Conversation
uncalibrated. Also adds a test.
322e157 to
54ea772
Compare
…ons, so that these values can be used as bounds to clip the calibrated forecast.
gavinevans
left a comment
There was a problem hiding this comment.
Thanks @Kat-90 👍
I've added a comment, as I don't think the original forecast that you're trying to compare to, is quite right, in terms of identifying the original forecast that we want to compare to. I've therefore created this PR (Kat-90#25) to your PR to identify the min and max within the original forecast and use these as the lower and bound when clipping the calibrated forecast.
| original_forecast = forecast_df.loc[ | ||
| forecast_df[representation_name] | ||
| == forecast_df[representation_name].iloc[0], | ||
| self.target_name, | ||
| ].values |
There was a problem hiding this comment.
There's an assumption in this pandas selection that we only want to use the zeroth item in forecast_df[representation_name] as the original forecast. This could be the 5th percentile, for example, or a single realization, and we don't really want to be clipping based on a single realization or the 5th percentile. I've therefore created a PR to this PR (Kat-90#25) with the aim of finding the min and max across realization or percentile, and using these values as the lower and upper bounds for clipping.
There was a problem hiding this comment.
Thanks Gavin, I've reviewed and merged in your changes.
Correction to "Forecast capping if calibrate forecast is too far from the uncalibrated"
mo-kbogue
left a comment
There was a problem hiding this comment.
Limited experience on the actual application of QRF in the suite but from what I can see it looks good. Just a few notes on possibly rewording some comments, and on the testing,
| provided, the forecast period found in the first forecast cube | ||
| will be used. | ||
| max_allowed_difference (float, optional): | ||
| The maximum allowed difference for the forecast calibration. If not |
There was a problem hiding this comment.
minor note but I'd prefer the below;
| The maximum allowed difference for the forecast calibration. If not | |
| The maximum allowed difference between the uncalibrated and calibrated forecast. If not |
| unique_site_id_keys: The names of the coordinates that uniquely identify | ||
| each site, e.g. "wmo_id" or ["latitude", "longitude"]. | ||
| max_allowed_difference (float, optional): | ||
| The maximum allowed difference for the forecast calibration. If not |
There was a problem hiding this comment.
Same as above, personally I'd go for;
| The maximum allowed difference for the forecast calibration. If not | |
| The maximum allowed difference between the uncalibrated and calibrated forecast. If not |
| provided, the first forecast period found in the forecast cube | ||
| will be used. | ||
| max_allowed_difference (float, optional): | ||
| The maximum allowed difference for the forecast calibration. If not |
There was a problem hiding this comment.
Same again
| The maximum allowed difference for the forecast calibration. If not | |
| The maximum allowed difference between the uncalibrated and calibrated forecast. If not |
| [0.5], | ||
| np.array([6], dtype=np.float32), | ||
| np.array([17.0, 0.0], dtype=np.float32), | ||
| 5.0, | ||
| np.array([11.0, 3.0], dtype=np.float32), |
There was a problem hiding this comment.
If I'm reading this correctly, we're inputting one single uncalibrated forecast value, 6, but our fake QRF calibrated forecast returns two values, 17 and 0? This test would maybe make more sense to me if the fake QRF calibrated forecast was 17 (rather than 17 and 0) and the expected output was 11 (rather than 11 and 3). Or equivalently, if the input forecast was [6.0, 6.0].
Some extra comments here might also just be useful, even if only for this first example, e.g the below;
| [0.5], | |
| np.array([6], dtype=np.float32), | |
| np.array([17.0, 0.0], dtype=np.float32), | |
| 5.0, | |
| np.array([11.0, 3.0], dtype=np.float32), | |
| [0.5], #50th percentile, i.e median | |
| np.array([6.0], [6.0], dtype=np.float32), #input uncalibrated forecast | |
| np.array([17.0, 0.0], dtype=np.float32), #qrf calibrated forecast | |
| 5.0, #maximum difference | |
| np.array([11.0, 3.0], dtype=np.float32), #expected output |
| ), | ||
| ( | ||
| [0.1, 0.5, 0.9], | ||
| np.array([6, 12, 18], dtype=np.float32), |
There was a problem hiding this comment.
As in the previous point, the uncalibrated and calibrated examples here not being the same length threw me off - might be better if they have the same format
| ), | ||
| ( | ||
| [0.1, 0.5, 0.9], | ||
| np.array([6, 12, 18], dtype=np.float32), |
| # 18 + 5 = 23 is the upper bound for the first site, while 6 - 5 = 3 is | ||
| # the lower bound for the second site. Values beyond these limits are | ||
| # clipped, while points already inside the allowed range remain unchanged. | ||
| np.array([[23.0, 23.0, 22.0], [3.0, 3.0, 9.0]], dtype=np.float32), |
There was a problem hiding this comment.
If we're inputting the 10th, 50th and 90th percentile as specified above, would we not expect the result to be in ascending order? Maybe that goes beyond the scope of this PR? Could be worth including as a warning perhaps
mo-kbogue
left a comment
There was a problem hiding this comment.
Thanks for the changes made - conversation offline helped me understand how this code works.
fa97707 to
fc753ee
Compare
mo-kbogue
left a comment
There was a problem hiding this comment.
Thanks for the changes made - conversation offline helped me understand how this code works.
…sion * upstream/master: Spatial morphing (metoppv#2441) Stochastic noise extensions (metoppv#2442) Forecast capping if calibrate forecast is too far from the uncalibrated (metoppv#2449) Vicinity metadata from the threshold plugin (metoppv#2439) Update cluster sources bookkeeping, so that forecast periods are only stored in one forecast source. (metoppv#2437) Correct realization numbering bug in temporal interpolation (metoppv#2436) Modify precedence ordering when clustering (metoppv#2435)
* master: Spatial Morphing - refinement of Google FILM output (#2451) Spatial morphing (#2441) Stochastic noise extensions (#2442) Forecast capping if calibrate forecast is too far from the uncalibrated (#2449) Vicinity metadata from the threshold plugin (#2439) Update cluster sources bookkeeping, so that forecast periods are only stored in one forecast source. (#2437)
Addresses #GitHubissuenum
This change adds a forecast cap, if set, that caps the calibrated forecast to an amount away from the original uncalibrated forecast. It acts as a risk mitigation for erroneous observations e.g. Fiji in the global calibration.
This is an optional argument that doesn't need to affect calibration of other diagnostics unless set in the suite.
Testing:
CLA