Skip to content

Feature/probability quantile matchers - #295

Draft
dsarmany wants to merge 19 commits into
developfrom
feature/probability-quantile-matchers
Draft

dsarmany wants to merge 19 commits into
developfrom
feature/probability-quantile-matchers

Conversation

@dsarmany

@dsarmany dsarmany commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Description

Contributor Declaration

By opening this pull request, I affirm the following:

  • All authors agree to the Contributor License Agreement.
  • The code follows the project's coding standards.
  • I have performed self-review and added comments where needed.
  • I have added or updated tests to verify that my changes are effective and functional.
  • I have run all existing tests and confirmed they pass.

📋 Metkit Documentation 📋
https://sites.ecmwf.int/docs/metkit/pull-requests/PR-295

MircoValentiniECMWF and others added 19 commits October 2, 2026 15:07
…ceholders

The placeholder operations only compiled with icpc, which does not check
discarded `if constexpr` branches strictly. With g++ and clang:

- referencePeriodEncoding.h: include the numberOfAdditionalParameters
  deduction and set_or_throw; the deductions that do not exist yet
  (numberOfReferencePeriodTimeRanges, the additional-parameter scale
  factors and values) become TODOs.
- quantileEncoding.h: declare Mars2GribConceptException before it is
  used, and drop the unreachable code after the throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Post-processed products carry the `postproc` block of PDT 4.89, 4.90,
4.133 and 4.135 (inputProcessIdentifier, inputOriginatingCentre,
typeOfPostProcessing). The concept is active for type=pfc (ecPoint
post-processed quantile forecasts). The encoding is a placeholder and
is never applied.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reference-period products

Section 4 recipes:
- 5/9 standard probabilities, 121/122 strike probabilities (no
  reference period: the large-ensemble templates have no such block),
  112/131 probabilities of (standardised) anomalies.
- 86/87 quantiles, 89/90 post-processed quantiles (pfc), 132-135
  quantiles of anomalies, 106/107 anomalies of members/derived products.
- Add the missing Section 4 registry entries (5, 9, 86, 87, 89, 90, 106,
  112, 132-135); without them the template number was never set.

Matchers:
- probability: type=ep only; StandardisedAnomaly 133093-133098, Anomaly
  131001-131010/131020-131025, StandardProbability 131060-131081,
  131085, 131098-131100, StrikeProbability 131089-131091.
- ensemble: ProbabilityLargeEnsemble only for strike probabilities.
- referencePeriod: efi/efic/sot, 133093-133098, ep anomaly
  probabilities, anomaly (171xxx, 173xxx) and significance (234xxx)
  parameters.
- quantile: has `quantile` and type != sot.
- statistics/pointInTime: probabilities that ecCodes defines without a
  statistic (131068, 131069, 131073, 131074-131081, 131089-131091) are
  point in time, or Maximum over a time window (GRIB1 timeRangeIndicator
  2); 133093-133098 windows are Average (ECC-2332); anomaly probabilities
  and anomaly/significance parameters are time means (tp anomalies are
  accumulations).
- level: anomaly probabilities (131001-131010), mean wave period
  thresholds (131078-131081), anomaly/significance parameters on the
  level of their base parameter.

Fixes in the WIP: Select<ProbabilityConcept, ...>, `range` in the
referencePeriod matcher, Anomaly in ProbabilityList, 131020 range, S4_R106
in the recipe list.

New test mars2grib-test-recipes-probability-quantile checks the Section 4
template selection without encoding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
68 headers under backend/deductions and backend/checks use the
dictionary traits but did not include them, so they only compiled when
an earlier include had pulled in dictionary_access_traits.h. Include it
where it is used. Each header now compiles on its own with g++.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The key was removed twice, so the second remove threw, and the success
path fell through to mars2marsUnreachable() without returning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MARS `quantile` is `<quantileValue>:<totalNumberOfQuantiles>` (e.g.
`10:100`), the form of the ecCodes `mars.quantile` alias. It is built from
the section-4 keys, so it does not depend on the ecCodes MARS definitions
of the input stream/type. Needed for quantile products such as enfo pfc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…antile`

In GRIB1 (local definition 19) the SOT percentile is MARS `number` (90 or
10), with the outer percentile in `efiOrder` (99 or 1). In GRIB2 the two
percentiles are reference-period parameters and ecCodes exposes them as
MARS `quantile` (ECC-2000): SOT90 is `90-99:100`, SOT10 is `1-10:100`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ducts

For type efi/efic/sot, pass numberOfForecastsInEnsemble, efiOrder and the
model climate of GRIB1 local definition 19
(numberOfReforecastYearsInModelClimate, sampleSizeOfModelClimate) to the
misc dictionary, for the referencePeriod and derived concepts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Processing)

Index products (EFI, SOT, ...) have two time ranges,
typeOfStatisticalProcessing = [102, X] (ecCodes grib2/paramId.def). The
ProductTimeSpec model already adds the outer IndexProcessing range
(shape IFSFakeSingleLoopDoubleLoop); pass it the inner statistic X of the
underlying field from a per-param table, and make the IndexProcessing
variant applicable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…roducts

- typeOfGeneratingProcess: type=pfc is a post-processed forecast (13);
  efi/efic/sot are ensemble-derived products (4), as em/es.
- derived ShiftOfTails: set numberOfForecastsInEnsemble (the SOT
  percentile is now MARS `quantile`, not `number`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Set totalNumberOfQuantiles and quantileValue from the MARS `quantile`
keyword (`<quantileValue>:<totalNumberOfQuantiles>`, validated by
metkit::Quantile).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For MARS type=pfc (ecPoint post-processed quantile forecasts) set the
post-processing keys of the operational GRIB2 products:
typeOfPostProcessing=206 (weather-type-subgrid-calibration),
inputProcessIdentifier=16, inputOriginatingCentre=98. Other types throw.

Test 012_enfo_pfc_quantile: pfc accumulation encodes as PDT 4.90 with
the quantile and post-processing keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
numberOfDaysInClimateSamplingWindow (GRIB1 local definition 19) is the
second reference-period time range of the model climate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
StageAllocate:
- numberOfAdditionalParametersForReferencePeriod: 2 for SOT, else from
  the parameter dictionary, else 0 (the deduction no longer throws).
- SOT: the two percentiles from MARS `quantile` (`90-99:100` -> {90, 99},
  `1-10:100` -> {10, 1}, ECC-2000), checked against efiOrder. Set before
  the local section, because ecCodes derives `mars.quantile` from them as
  soon as `marsStream` is set.
- Model climate time ranges from the parameter dictionary:
  numberOfReforecastYearsInModelClimate (years) and
  numberOfDaysInClimateSamplingWindow (days).

StagePreset:
- efi/efic/sot: typeOfReferenceDataset=2 (reforecast),
  typeOfRelationToReferenceDataset 20 (EFI) / 21 (SOT); for the other
  products the relation follows from the paramId.
- sampleSizeOfReferencePeriod from sampleSizeOfModelClimate.

The start of the reference period is not encoded yet (TODO): it is not
part of the input metadata.

Test 013_enfo_index_products: efi, efic, SOT90 and SOT10 (PDT 4.107).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
probabilityType and the probability limits are defined per paramId in
ecCodes and set with the `param` concept, so the probability concept has
nothing else to encode. Drop the "not implemented" warnings that were
printed for every strike, standardised-anomaly and anomaly field.

Test 014_enfo_probabilities: tp probability over 24h (PDT 4.9), 10m wind
speed probability instant (4.5) and over a time window (4.9, maximum),
strike probability over 48h (4.122), probability of a standardised
anomaly (4.131).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
typeOfGeneratingProcess had no mapping for type=ep, so the value of the
sample (0, analysis) was kept. Use 5 (probability forecast).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.35245% with 75 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.65%. Comparing base (3186ba1) to head (4bc9039).

Files with missing lines Patch % Lines
src/metkit/grib2mars/mappings/rules/quantile.h 0.00% 11 Missing ⚠️
...oncepts/reference-period/referencePeriodEncoding.h 86.44% 8 Missing ⚠️
...b/backend/concepts/statistics/statisticsEncoding.h 66.66% 7 Missing ⚠️
...s/numberOfAdditionalParametersForReferencePeriod.h 56.25% 7 Missing ⚠️
...ests/mars2grib/encoding/013_enfo_index_products.cc 94.59% 6 Missing ⚠️
...end/mars2grib-test-recipes-probability-quantile.cc 95.00% 5 Missing ⚠️
tests/mars2grib/encoding/012_enfo_pfc_quantile.cc 89.79% 5 Missing ⚠️
tests/mars2grib/encoding/014_enfo_probabilities.cc 93.58% 5 Missing ⚠️
.../concepts/post-processing/postProcessingEncoding.h 66.66% 4 Missing ⚠️
tests/mars2mars/mars2mars-test-04.cc 90.00% 4 Missing ⚠️
... and 5 more
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #295      +/-   ##
===========================================
+ Coverage    50.96%   53.65%   +2.69%     
===========================================
  Files          481      497      +16     
  Lines        22812    23391     +579     
  Branches      1569     1587      +18     
===========================================
+ Hits         11625    12551     +926     
+ Misses       11187    10840     -347     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dsarmany
dsarmany marked this pull request as draft October 2, 2026 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants