From 61f3ead93bc8741404a71b5d73cd5bdcd44eeede Mon Sep 17 00:00:00 2001 From: Jared Lewis Date: Wed, 2 Sep 2026 18:03:54 +1000 Subject: [PATCH 1/6] feat: separate obs4REF reference data from published obs4MIPs Reworks the diagnostic reference dataset metadata so it matches the datasets the providers actually select, and so a reader can tell published data from our pre-release data. - Names each dataset by who supplies it, so a dataset required as `obs4mips` but served ahead of publication now reads `obs4ref.HadISST-1-1`. - Adds a `source` field carrying the same thing in a structured form, with a test that keeps it in step with the name. - Corrects the source ids against the providers' data requirements, so ILAMB and PMP datasets are labelled from the providers rather than from a mix of guesses. - Adds the five ozone diagnostics, and drops `pmp/enso_perf` and the AMO mode, which the providers no longer register. - Fixes the ILAMB `emp-gleamgpcp2.3` key, which never matched the diagnostic slug. The reference dataset cards now float the primary/secondary badge to the top right, because the dataset itself matters more than its role. --- .../ref_backend/core/diagnostic_metadata.py | 41 ++++- backend/static/diagnostics/esmvaltool.yaml | 162 +++++++++++++----- backend/static/diagnostics/ilamb.yaml | 84 +++++---- backend/static/diagnostics/pmp.yaml | 117 ++++++------- .../test_core/test_diagnostic_metadata.py | 70 ++++++++ changelog/74.improvement.md | 6 + frontend/src/client/types.gen.ts | 14 +- .../route.tsx | 19 +- 8 files changed, 363 insertions(+), 150 deletions(-) create mode 100644 changelog/74.improvement.md diff --git a/backend/src/ref_backend/core/diagnostic_metadata.py b/backend/src/ref_backend/core/diagnostic_metadata.py index d197bc88..833cd260 100644 --- a/backend/src/ref_backend/core/diagnostic_metadata.py +++ b/backend/src/ref_backend/core/diagnostic_metadata.py @@ -17,6 +17,23 @@ from loguru import logger from pydantic import BaseModel, Field +ReferenceDatasetSource = Literal[ + "obs4mips", + "obs4ref", + "pmp-climatology", + "esmvaltool-reference", + "ilamb", + "recipe", +] +""" +Where a reference dataset comes from. + +The source type alone does not say this. Most of the datasets a diagnostic requires as +``obs4mips`` are served by the REF's own obs4REF collection ahead of publication, so the +distinction between officially published data and pre-release data has to be recorded here. +This mirrors the prefix on ``ReferenceDatasetLink.slug``. +""" + class ReferenceDatasetLink(BaseModel): """ @@ -26,10 +43,29 @@ class ReferenceDatasetLink(BaseModel): compare model outputs against. They can be classified by their role in the analysis. """ - slug: str = Field(..., description="Unique identifier for the dataset(e.g., 'obs4mips.CERES-EBAF.v4.2')") + slug: str = Field( + ..., + description=( + "Unique identifier for the dataset, `.`. The prefix names who " + "supplies the data rather than the source type the requirement asks for, so a dataset " + "required as obs4mips but served pre-release reads 'obs4ref.HadISST-1-1'" + ), + ) description: str | None = Field( None, description="Description of how this dataset is used in the diagnostic" ) + source: ReferenceDatasetSource | None = Field( + None, + description=( + "Where the data comes from, which is not the same as its source type:\n" + "- 'obs4mips': published on ESGF obs4MIPs\n" + "- 'obs4ref': pre-release reference data served by the REF, not yet on obs4MIPs\n" + "- 'pmp-climatology': the PMP climatology registry\n" + "- 'esmvaltool-reference': the ESMValTool reference registry\n" + "- 'ilamb': the ILAMB registry\n" + "- 'recipe': named inside the provider's recipe rather than ingested by the REF" + ), + ) type: Literal["primary", "secondary", "comparison"] = Field( ..., description=( @@ -121,7 +157,8 @@ def load_diagnostic_metadata(path: Path) -> dict[str, DiagnosticMetadata]: pmp/annual-cycle: reference_datasets: - - slug: "obs4mips.CERES-EBAF.v4.2" + - slug: "obs4mips.CERES-EBAF-4-2-1" + source: "obs4mips" description: "CERES Energy Balanced and Filled" type: "primary" display_name: "Annual Cycle Analysis" diff --git a/backend/static/diagnostics/esmvaltool.yaml b/backend/static/diagnostics/esmvaltool.yaml index 24841cc6..4a6163f9 100644 --- a/backend/static/diagnostics/esmvaltool.yaml +++ b/backend/static/diagnostics/esmvaltool.yaml @@ -1,18 +1,17 @@ # ESMValTool Diagnostic Metadata # # Reference datasets and display metadata for ESMValTool diagnostics. +# +# `slug` is `.`, and `source` says the same thing in a structured field. +# The prefix names who supplies the data, not the source type the requirement asks for, so a +# dataset required as `obs4mips` but served pre-release reads `obs4ref.HadISST-1-1`. esmvaltool/cloud-radiative-effects: reference_datasets: - - slug: "esmvaltool.CERES-EBAF" - description: "CERES Energy Balanced and Filled - TOA radiation fluxes (rlut, rlutcs, rsut, rsutcs) (planned to move to obs4MIPs)" + - slug: "obs4mips.CERES-EBAF-4-2-1" + source: "obs4mips" + description: "CERES Energy Balanced and Filled v4.2.1. Supplies rlut, rlutcs, rsut and rsutcs." type: "primary" - - slug: "esmvaltool.ESACCI-CLOUD" - description: "ESA CCI Cloud properties (planned to move to obs4MIPs)" - type: "secondary" - - slug: "esmvaltool.ISCCP-FH" - description: "ISCCP cloud properties (planned to move to obs4MIPs)" - type: "secondary" display_name: "Cloud Radiative Effects" description: >- Plot climatologies and zonal mean profiles of cloud radiative effects @@ -21,11 +20,9 @@ esmvaltool/cloud-radiative-effects: esmvaltool/cloud-scatterplots-cli-ta: reference_datasets: - - slug: "obs4mips.ERA-5" - description: "ERA5 - Air temperature (ta)" - type: "primary" - slug: "esmvaltool.CALIPSO-ICECLOUD" - description: "CALIPSO - Ice cloud properties (cli), baked into recipe" + source: "recipe" + description: "CALIPSO ice cloud properties. Supplies cli, named in the recipe." type: "secondary" display_name: "Cloud-Temperature Scatterplots (cli vs ta)" description: >- @@ -37,10 +34,12 @@ esmvaltool/cloud-scatterplots-cli-ta: esmvaltool/cloud-scatterplots-clivi-lwcre: reference_datasets: - slug: "esmvaltool.CERES-EBAF" - description: "CERES Energy Balanced and Filled - Longwave radiation (rlut, rlutcs; lwcre derived), baked into recipe" + source: "recipe" + description: "CERES Energy Balanced and Filled. Supplies rlut and rlutcs (lwcre derived), named in the recipe." type: "primary" - slug: "esmvaltool.ESACCI-CLOUD" - description: "ESA CCI Cloud properties - Ice water path (clivi), baked into recipe" + source: "recipe" + description: "ESA CCI cloud properties. Supplies clivi, named in the recipe." type: "secondary" display_name: "Cloud-Radiation Scatterplots (clivi vs lwcre)" description: "Scatterplot of ice water path (clivi) vs longwave cloud radiative effect (lwcre)." @@ -49,10 +48,12 @@ esmvaltool/cloud-scatterplots-clivi-lwcre: esmvaltool/cloud-scatterplots-clt-swcre: reference_datasets: - slug: "esmvaltool.CERES-EBAF" - description: "CERES Energy Balanced and Filled - Shortwave radiation (rsut, rsutcs; swcre derived), baked into recipe" + source: "recipe" + description: "CERES Energy Balanced and Filled. Supplies rsut and rsutcs (swcre derived), named in the recipe." type: "primary" - slug: "esmvaltool.ESACCI-CLOUD" - description: "ESA CCI Cloud properties - Total cloud fraction (clt), baked into recipe" + source: "recipe" + description: "ESA CCI cloud properties. Supplies clt, named in the recipe." type: "secondary" display_name: "Cloud-Radiation Scatterplots (clt vs swcre)" description: "Scatterplot of total cloud fraction (clt) vs shortwave cloud radiative effect (swcre)." @@ -60,14 +61,17 @@ esmvaltool/cloud-scatterplots-clt-swcre: esmvaltool/cloud-scatterplots-clwvi-pr: reference_datasets: - - slug: "obs4MIPs.GPCPv2.3" - description: "GPCP v2.3 - Precipitation (pr)" + - slug: "esmvaltool.GPCP-V2.3" + source: "recipe" + description: "GPCP v2.3. Supplies pr, named in the recipe." type: "secondary" - slug: "esmvaltool.ESACCI-CLOUD" - description: "ESA CCI Cloud properties (clwvi, planned to move to obs4MIPs)" + source: "recipe" + description: "ESA CCI cloud properties. Supplies clwvi, named in the recipe." type: "secondary" - slug: "esmvaltool.CERES-EBAF" - description: "CERES Energy Balanced and Filled - Radiation, baked into recipe" + source: "recipe" + description: "CERES Energy Balanced and Filled. Supplies the radiation fields, named in the recipe." type: "primary" display_name: "Cloud-Precipitation Scatterplots (clwvi vs pr)" description: "Scatterplot of condensed water path (clwvi) vs precipitation (pr)." @@ -76,19 +80,24 @@ esmvaltool/cloud-scatterplots-clwvi-pr: esmvaltool/cloud-scatterplots-reference: reference_datasets: - slug: "obs4mips.ERA-5" - description: "ERA5 - Air temperature (ta), ingested via REF" + source: "obs4mips" + description: "ERA5 reanalysis. Supplies ta over 2007 to 2014." type: "primary" - slug: "esmvaltool.CERES-EBAF" - description: "CERES Energy Balanced and Filled - Radiation, baked into recipe" + source: "recipe" + description: "CERES Energy Balanced and Filled. Supplies the radiation fields, named in the recipe." type: "primary" - slug: "esmvaltool.CALIPSO-ICECLOUD" - description: "CALIPSO - Ice cloud properties (cli), baked into recipe" + source: "recipe" + description: "CALIPSO ice cloud properties. Supplies cli, named in the recipe." type: "secondary" - slug: "esmvaltool.ESACCI-CLOUD" - description: "ESA CCI Cloud properties (clt, clwvi, clivi), baked into recipe" + source: "recipe" + description: "ESA CCI cloud properties. Supplies clt, clwvi and clivi, named in the recipe." type: "secondary" - slug: "esmvaltool.GPCP-V2.3" - description: "GPCP v2.3 - Precipitation (pr), hardcoded in update_recipe" + source: "recipe" + description: "GPCP v2.3. Supplies pr, named in the recipe because it cannot be ingested (climate-ref issue 260)." type: "secondary" display_name: "Cloud Scatterplots for Reference dataset" description: >- @@ -99,10 +108,12 @@ esmvaltool/cloud-scatterplots-reference: esmvaltool/enso-basic-climatology: reference_datasets: - slug: "esmvaltool.GPCP-V2.3" - description: "GPCP v2.3 - Precipitation (pr), baked into recipe" + source: "recipe" + description: "GPCP v2.3. Supplies pr, named in the recipe." type: "secondary" - slug: "esmvaltool.TROPFLUX" - description: "TROPFLUX (OBS6) - Sea surface temperature (tos) and wind stress (tauu), baked into recipe" + source: "recipe" + description: "TropFlux. Supplies tos and tauu, named in the recipe." type: "secondary" display_name: "ENSO Basic Climatology" description: >- @@ -113,7 +124,8 @@ esmvaltool/enso-basic-climatology: esmvaltool/enso-characteristics: reference_datasets: - slug: "esmvaltool.TROPFLUX" - description: "TROPFLUX (OBS6) - Sea surface temperature (tos), hardcoded in update_recipe" + source: "recipe" + description: "TropFlux. Supplies tos, named in the recipe." type: "primary" display_name: "ENSO Characteristics" description: >- @@ -121,6 +133,54 @@ esmvaltool/enso-characteristics: evaluating the amplitude, frequency, and spatial structure of ENSO events. tags: ["ocean", "enso", "variability"] +esmvaltool/ozone-annual-cycle: + reference_datasets: + - slug: "obs4mips.C3S-GTO-ECV-9-0" + source: "obs4mips" + description: "C3S GTO-ECV total column ozone v9.0. Supplies toz." + type: "primary" + display_name: "Ozone Annual Cycle" + description: "Plot the zonal mean total column ozone (toz) against the annual cycle." + tags: ["atmosphere", "ozone", "seasonal-cycle"] + +esmvaltool/ozone-lat-time: + reference_datasets: + - slug: "obs4mips.C3S-GTO-ECV-9-0" + source: "obs4mips" + description: "C3S GTO-ECV total column ozone v9.0. Supplies toz." + type: "primary" + display_name: "Ozone Latitude vs Time" + description: "Plot the zonal mean total column ozone (toz) against time." + tags: ["atmosphere", "ozone", "timeseries"] + +esmvaltool/ozone-nh-mar: + reference_datasets: + - slug: "obs4mips.C3S-GTO-ECV-9-0" + source: "obs4mips" + description: "C3S GTO-ECV total column ozone v9.0. Supplies toz." + type: "primary" + display_name: "Ozone Northern Polar Cap (March)" + description: "Plot the March Northern Hemisphere polar mean (60N to 80N) total column ozone (toz) time series." + tags: ["atmosphere", "ozone", "polar"] + +esmvaltool/ozone-sh-oct: + reference_datasets: + - slug: "obs4mips.C3S-GTO-ECV-9-0" + source: "obs4mips" + description: "C3S GTO-ECV total column ozone v9.0. Supplies toz." + type: "primary" + display_name: "Ozone Southern Polar Cap (October)" + description: "Plot the October Southern Hemisphere polar mean (60S to 85S) total column ozone (toz) time series." + tags: ["atmosphere", "ozone", "polar"] + +esmvaltool/ozone-zonal: + reference_datasets: [] + display_name: "Ozone Zonal Mean Profiles" + description: >- + Plot the stratospheric zonal mean ozone (o3) profiles. No reference dataset is used yet, + because ESACCI-OZONE (SAGE-OMPS) is not on obs4MIPs. + tags: ["atmosphere", "ozone", "stratosphere"] + esmvaltool/equilibrium-climate-sensitivity: reference_datasets: [] display_name: "Equilibrium Climate Sensitivity (ECS)" @@ -161,16 +221,20 @@ esmvaltool/zero-emission-commitment: esmvaltool/regional-historical-annual-cycle: reference_datasets: - slug: "obs4mips.ERA-5" - description: "ERA-5 - Sea level pressure (psl) and zonal wind (ua), ingested via REF" + source: "obs4mips" + description: "ERA5 reanalysis. Supplies psl and ua." type: "primary" - slug: "esmvaltool.HadCRUT5" - description: "HadCRUT5 v5.0.1.0-analysis - Near-surface air temperature (tas), hardcoded in recipe" + source: "recipe" + description: "HadCRUT5 v5.0.1.0 analysis. Supplies tas, named in the recipe." type: "secondary" - slug: "esmvaltool.GPCP-V2.3" - description: "GPCP v2.3 - Precipitation (pr), hardcoded in recipe (cannot be ingested, issue #260)" + source: "recipe" + description: "GPCP v2.3. Supplies pr, named in the recipe because it cannot be ingested (climate-ref issue 260)." type: "secondary" - slug: "esmvaltool.ERA5-native6" - description: "ERA5 native6 - Specific humidity (hus), not yet on obs4MIPs" + source: "recipe" + description: "ERA5 native6. Supplies hus, which is not on obs4MIPs." type: "secondary" display_name: "Regional Historical Annual Cycle" description: >- @@ -183,16 +247,20 @@ esmvaltool/regional-historical-annual-cycle: esmvaltool/regional-historical-timeseries: reference_datasets: - slug: "obs4mips.ERA-5" - description: "ERA-5 - Sea level pressure (psl) and zonal wind (ua), ingested via REF" + source: "obs4mips" + description: "ERA5 reanalysis. Supplies psl and ua." type: "primary" - slug: "esmvaltool.HadCRUT5" - description: "HadCRUT5 v5.0.1.0-analysis - Near-surface air temperature (tas), hardcoded in recipe" + source: "recipe" + description: "HadCRUT5 v5.0.1.0 analysis. Supplies tas, named in the recipe." type: "secondary" - slug: "esmvaltool.GPCP-V2.3" - description: "GPCP v2.3 - Precipitation (pr), hardcoded in recipe (cannot be ingested, issue #260)" + source: "recipe" + description: "GPCP v2.3. Supplies pr, named in the recipe because it cannot be ingested (climate-ref issue 260)." type: "secondary" - slug: "esmvaltool.ERA5-native6" - description: "ERA5 native6 - Specific humidity (hus), not yet on obs4MIPs" + source: "recipe" + description: "ERA5 native6. Supplies hus, which is not on obs4MIPs." type: "secondary" display_name: "Regional Historical Timeseries" description: >- @@ -205,16 +273,20 @@ esmvaltool/regional-historical-timeseries: esmvaltool/regional-historical-trend: reference_datasets: - slug: "obs4mips.ERA-5" - description: "ERA-5 - Sea level pressure (psl), near-surface air temperature (tas), and zonal wind (ua), ingested via REF" + source: "obs4mips" + description: "ERA5 reanalysis. Supplies psl, tas and ua." type: "primary" - slug: "esmvaltool.HadCRUT5" - description: "HadCRUT5 v5.0.1.0-analysis - Near-surface air temperature (tas), hardcoded in recipe" + source: "recipe" + description: "HadCRUT5 v5.0.1.0 analysis. Supplies tas, named in the recipe." type: "secondary" - slug: "esmvaltool.GPCP-V2.3" - description: "GPCP v2.3 - Precipitation (pr), hardcoded in recipe (cannot be ingested, issue #260)" + source: "recipe" + description: "GPCP v2.3. Supplies pr, named in the recipe because it cannot be ingested (climate-ref issue 260)." type: "secondary" - slug: "esmvaltool.ERA5-native6" - description: "ERA5 native6 - Specific humidity (hus) and precipitation (pr), hardcoded in recipe" + source: "recipe" + description: "ERA5 native6. Supplies hus and pr, named in the recipe." type: "secondary" display_name: "Regional Historical Trends" description: >- @@ -226,11 +298,13 @@ esmvaltool/regional-historical-trend: esmvaltool/sea-ice-area-basic: reference_datasets: - - slug: "esmvaltool.OSI-450-nh" - description: "OSI-450 v3 - Sea ice concentration (siconc), Northern Hemisphere, hardcoded in recipe" + - slug: "esmvaltool-reference.OSI-450-nh" + source: "esmvaltool-reference" + description: "OSI-450 v3 Northern Hemisphere. Supplies sic and areacello." type: "primary" - - slug: "esmvaltool.OSI-450-sh" - description: "OSI-450 v3 - Sea ice concentration (siconc), Southern Hemisphere, hardcoded in recipe" + - slug: "esmvaltool-reference.OSI-450-sh" + source: "esmvaltool-reference" + description: "OSI-450 v3 Southern Hemisphere. Supplies sic and areacello." type: "primary" display_name: "Arctic and Antarctic Sea Ice Area Seasonal Cycle" description: >- diff --git a/backend/static/diagnostics/ilamb.yaml b/backend/static/diagnostics/ilamb.yaml index 3714288b..cecb4720 100644 --- a/backend/static/diagnostics/ilamb.yaml +++ b/backend/static/diagnostics/ilamb.yaml @@ -2,19 +2,26 @@ # # Reference datasets and display metadata for ILAMB (International Land Model # Benchmarking) and IOMB (International Ocean Model Benchmarking) diagnostics. +# +# `slug` is `.`, and `source` says the same thing in a structured field. +# The prefix names who supplies the data, not the source type the requirement asks for, so a +# dataset required as `obs4mips` but served pre-release reads `obs4ref.HadISST-1-1`. # Land diagnostics ilamb/gpp-wecann: reference_datasets: - - slug: "obs4REF.WECANN" - description: "WECANN GPP dataset - Gross primary productivity (gpp)" + - slug: "obs4ref.WECANN-1-0" + source: "obs4ref" + description: "WECANN v1.0. Supplies gpp." type: "primary" - - slug: "obs4REF.GPCPv2.3" - description: "GPCP v2.3 - Precipitation (pr), relationship dataset" + - slug: "obs4ref.GPCP-2-3" + source: "obs4ref" + description: "GPCP v2.3. Supplies pr for the relationship analysis." type: "secondary" - slug: "ilamb.CRU4.02" - description: "CRU TS v4.02 - Near-surface air temperature (tas), relationship dataset" + source: "ilamb" + description: "CRU TS v4.02. Supplies tas for the relationship analysis." type: "secondary" display_name: "Gross Primary Productivity (WECANN)" description: "Apply the standard ILAMB analysis of gross primary productivity (gpp) with respect to the WECANN reference dataset." @@ -22,8 +29,9 @@ ilamb/gpp-wecann: ilamb/gpp-fluxnet2015: reference_datasets: - - slug: "obs4REF.FLUXNET2015" - description: "FLUXNET2015 - Tower-based GPP measurements" + - slug: "obs4ref.FLUXNET2015-1-0" + source: "obs4ref" + description: "FLUXNET2015 v1.0 tower sites. Supplies gpp, referenced by registry key rather than ingested facets." type: "primary" display_name: "Gross Primary Productivity (FLUXNET2015)" description: "Apply the standard ILAMB analysis of gross primary productivity (gpp) with respect to the FLUXNET2015 tower-based reference dataset." @@ -31,8 +39,9 @@ ilamb/gpp-fluxnet2015: ilamb/mrro-lora: reference_datasets: - - slug: "obs4REF.LORA" - description: "LORA dataset - Runoff observations" + - slug: "obs4ref.LORA-1-0" + source: "obs4ref" + description: "LORA v1.0. Supplies mrro." type: "primary" display_name: "Runoff (LORA)" description: "Apply the standard ILAMB analysis of total runoff (mrro) with respect to the LORA reference dataset." @@ -40,8 +49,9 @@ ilamb/mrro-lora: ilamb/mrsos-wangmao: reference_datasets: - - slug: "obs4REF.WangMao" - description: "Wang-Mao dataset - Soil moisture (mrsos)" + - slug: "ilamb.WangMao" + source: "ilamb" + description: "Wang and Mao soil moisture. Supplies mrsol, converted to a surface volumetric fraction." type: "primary" display_name: "Surface Soil Moisture (WangMao)" description: "Apply the standard ILAMB analysis of moisture in upper portion of soil column (mrsos) with respect to the WangMao reference dataset." @@ -49,8 +59,9 @@ ilamb/mrsos-wangmao: ilamb/csoil-hwsd2: reference_datasets: - - slug: "obs4REF.HWSD2" - description: "Harmonized World Soil Database v2 - Soil carbon content" + - slug: "obs4ref.HWSD-2-0" + source: "obs4ref" + description: "Harmonized World Soil Database v2.0. Supplies cSoil." type: "primary" display_name: "Soil Carbon (HWSD2)" description: "Apply the standard ILAMB analysis of carbon mass in soil pool (cSoil) with respect to the HWSD2 reference dataset." @@ -58,8 +69,9 @@ ilamb/csoil-hwsd2: ilamb/lai-avh15c1: reference_datasets: - - slug: "obs4REF.AVH15C1" - description: "AVHRR - Leaf area index observations" + - slug: "obs4mips.NOAA-NCEI-LAI-AVHRR-5-0" + source: "obs4mips" + description: "NOAA NCEI AVHRR leaf area index v5.0. Supplies lai, coarsened to a common grid before comparison." type: "primary" display_name: "Leaf Area Index (AVH15C1)" description: "Apply the standard ILAMB analysis of leaf area index (lai) with respect to the AVH15C1 (AVHRR) reference dataset." @@ -67,8 +79,9 @@ ilamb/lai-avh15c1: ilamb/nbp-hoffman: reference_datasets: - - slug: "obs4REF.Hoffman" - description: "Hoffman dataset - Net biome productivity" + - slug: "obs4ref.Hoffman-1-0" + source: "obs4ref" + description: "Hoffman v1.0. Supplies nbp as a global mean." type: "primary" display_name: "Net Biome Productivity (Hoffman)" description: "Apply the standard ILAMB analysis of net biome productivity (nbp) with respect to the Hoffman reference dataset." @@ -76,8 +89,9 @@ ilamb/nbp-hoffman: ilamb/snc-esacci: reference_datasets: - - slug: "obs4REF.CCI-CryoClim-FSC" - description: "ESA CCI Snow - Snow cover fraction" + - slug: "obs4ref.CCI-CryoClim-FSC-1" + source: "obs4ref" + description: "ESA CCI CryoClim fractional snow cover v1. Supplies snc." type: "primary" display_name: "Snow Cover (ESA CCI)" description: "Apply the standard ILAMB analysis of snow cover fraction (snc) with respect to the ESA CCI CryoClim fractional snow cover reference dataset." @@ -85,20 +99,23 @@ ilamb/snc-esacci: ilamb/burntfractionall-gfed: reference_datasets: - - slug: "obs4REF.GFED" - description: "Global Fire Emissions Database - Burnt area fraction" + - slug: "obs4ref.GFED-5-0" + source: "obs4ref" + description: "Global Fire Emissions Database v5.0. Supplies burntFractionAll." type: "primary" display_name: "Burnt Fraction (GFED)" description: "Apply the standard ILAMB analysis of burnt area fraction (burntFractionAll) with respect to the GFED reference dataset." tags: ["land", "fire", "disturbance"] -ilamb/emp-gleamgpcp: +ilamb/emp-gleamgpcp2.3: reference_datasets: - - slug: "obs4REF.GLEAMv3.3a" - description: "GLEAM v3.3a - Evapotranspiration (et)" + - slug: "ilamb.GLEAMv3.3a" + source: "ilamb" + description: "GLEAM v3.3a. Supplies evapotranspiration (et)." type: "primary" - - slug: "obs4REF.GPCP-2-3" - description: "GPCP v2.3 (obs4REF) - Precipitation (pr)" + - slug: "obs4ref.GPCP-2-3" + source: "obs4ref" + description: "GPCP v2.3. Supplies pr." type: "primary" display_name: "Evaporation minus Precipitation (GLEAM/GPCP)" description: "Apply the standard ILAMB analysis of evaporation minus precipitation (E-P) using GLEAMv3.3a evapotranspiration and GPCP v2.3 precipitation reference datasets." @@ -108,8 +125,9 @@ ilamb/emp-gleamgpcp: ilamb/thetao-woa2023-surface: reference_datasets: - - slug: "obs4REF.WOA2023" - description: "World Ocean Atlas 2023 - Sea water potential temperature (thetao, surface, mapped to tos)" + - slug: "obs4ref.WOA-23" + source: "obs4ref" + description: "World Ocean Atlas 2023 monthly climatology (2005 to 2022). Supplies thetao, taken at the surface." type: "primary" display_name: "Sea Water Temperature (WOA2023 Surface)" description: "Apply the standard ILAMB analysis of sea water potential temperature (thetao) at the surface with respect to the WOA2023 reference dataset." @@ -117,8 +135,9 @@ ilamb/thetao-woa2023-surface: ilamb/so-woa2023-surface: reference_datasets: - - slug: "obs4REF.WOA2023" - description: "World Ocean Atlas 2023 - Sea water salinity (so, surface)" + - slug: "obs4ref.WOA-23" + source: "obs4ref" + description: "World Ocean Atlas 2023 monthly climatology (2005 to 2022). Supplies so, taken at the surface." type: "primary" display_name: "Sea Water Salinity (WOA2023 Surface)" description: "Apply the standard ILAMB analysis of sea water salinity (so) at the surface with respect to the WOA2023 reference dataset." @@ -126,8 +145,9 @@ ilamb/so-woa2023-surface: ilamb/amoc-rapid: reference_datasets: - - slug: "obs4REF.RAPID" - description: "RAPID array - Atlantic Meridional Overturning Circulation (amoc, from msftmz)" + - slug: "obs4ref.RAPID-2023-1a" + source: "obs4ref" + description: "RAPID array 2023 release 1a. Supplies msftmz, transformed into the RAPID AMOC index." type: "primary" display_name: "Atlantic Meridional Overturning Circulation (RAPID)" description: "Apply the standard ILAMB analysis of the Atlantic Meridional Overturning Circulation (AMOC) with respect to the RAPID array reference dataset." diff --git a/backend/static/diagnostics/pmp.yaml b/backend/static/diagnostics/pmp.yaml index 0af94010..789dd16d 100644 --- a/backend/static/diagnostics/pmp.yaml +++ b/backend/static/diagnostics/pmp.yaml @@ -1,17 +1,24 @@ # PMP Diagnostic Metadata # # Reference datasets and display metadata for PMP (PCMDI Metrics Package) diagnostics. +# +# `slug` is `.`, and `source` says the same thing in a structured field. +# The prefix names who supplies the data, not the source type the requirement asks for, so a +# dataset required as `obs4mips` but served pre-release reads `obs4ref.HadISST-1-1`. pmp/annual-cycle: reference_datasets: - - slug: "obs4MIPs-climatology.ERA-5" - description: "ERA5 Reanalysis - Primary climatology for surface temperature (ts), winds (uas, vas), sea level pressure (psl), air temperature (ta), zonal/meridional wind (ua, va), and geopotential height (zg). Period: 1981-2004." + - slug: "pmp-climatology.ERA-5" + source: "pmp-climatology" + description: "ERA5 reanalysis climatology. Supplies ts, uas, vas, psl, ta, ua, va and zg." type: "primary" - - slug: "obs4MIPs-climatology.GPCP-Monthly-3-2" - description: "Global Precipitation Climatology Project v3.2 - Precipitation reference (pr). Period: 1983-2004." + - slug: "pmp-climatology.GPCP-3-3" + source: "pmp-climatology" + description: "Global Precipitation Climatology Project v3.3 climatology. Supplies pr." type: "primary" - - slug: "obs4MIPs-climatology.CERES-EBAF-4-2" - description: "CERES Energy Balanced and Filled v4.2 - Radiation fields (rlds, rlus, rlut, rsds, rsdt, rsus, rsut) and clear-sky variants (rldscs, rsdscs, rlutcs, rsutcs, rsuscs, rltcre, rstcre, rt). Period: 2001-2004." + - slug: "pmp-climatology.CERES-EBAF-4-2" + source: "pmp-climatology" + description: "CERES Energy Balanced and Filled v4.2 climatology. Supplies rlds, rlus, rlut, rsds, rsdt, rsus and rsut." type: "primary" display_name: "Annual Cycle Analysis" description: >- @@ -21,33 +28,19 @@ pmp/annual-cycle: (rlds, rlus, rsds, rsdt, rsus, rlut, rsut) including clear-sky variants. tags: ["atmosphere", "seasonal-cycle", "climatology"] -pmp/enso_perf: - reference_datasets: - - slug: "obs4mips.GPCP-Monthly-3-2" - description: "Global Precipitation Climatology Project v3.2 - Precipitation (pr)" - type: "primary" - - slug: "obs4mips.TropFlux-1-0" - description: "TropFlux v1.0 - Wind stress (tauu)" - type: "primary" - - slug: "obs4mips.HadISST-1-1" - description: "Hadley Centre Sea Ice and Sea Surface Temperature v1.1 - Sea surface temperature (ts)" - type: "primary" - display_name: "ENSO Performance Metrics" - description: >- - Calculate the ENSO performance metrics for a dataset. These metrics evaluate - how well a model simulates key aspects of El Nino-Southern Oscillation variability. - tags: ["ocean", "atmosphere", "enso", "variability"] - pmp/enso_tel: reference_datasets: - - slug: "obs4mips.GPCP-Monthly-3-2" - description: "Global Precipitation Climatology Project v3.2 - Precipitation teleconnections (pr)" + - slug: "obs4ref.GPCP-Monthly-3-2" + source: "obs4ref" + description: "Global Precipitation Climatology Project v3.2. Supplies pr." type: "primary" - - slug: "obs4mips.TropFlux-1-0" - description: "TropFlux v1.0 - Wind stress (tauu)" + - slug: "obs4ref.HadISST-1-1" + source: "obs4ref" + description: "Hadley Centre Sea Ice and Sea Surface Temperature v1.1. Supplies ts." type: "primary" - - slug: "obs4mips.HadISST-1-1" - description: "Hadley Centre Sea Ice and SST v1.1 - Sea surface temperature teleconnections (ts)" + - slug: "obs4ref.TropFlux-1-0" + source: "obs4ref" + description: "TropFlux v1.0. Supplies air/sea flux and surface fields over the tropical oceans." type: "primary" display_name: "ENSO Teleconnections" description: >- @@ -58,17 +51,21 @@ pmp/enso_tel: pmp/enso_proc: reference_datasets: - - slug: "obs4mips.GPCP-Monthly-3-2" - description: "Global Precipitation Climatology Project v3.2 - Precipitation (pr)" + - slug: "obs4ref.GPCP-Monthly-3-2" + source: "obs4ref" + description: "Global Precipitation Climatology Project v3.2. Supplies pr." type: "primary" - - slug: "obs4mips.TropFlux-1-0" - description: "TropFlux v1.0 - Wind stress (tauu)" + - slug: "obs4ref.HadISST-1-1" + source: "obs4ref" + description: "Hadley Centre Sea Ice and Sea Surface Temperature v1.1. Supplies ts." type: "primary" - - slug: "obs4mips.HadISST-1-1" - description: "Hadley Centre Sea Ice and SST v1.1 - Sea surface temperature (ts)" + - slug: "obs4ref.TropFlux-1-0" + source: "obs4ref" + description: "TropFlux v1.0. Supplies zonal wind stress (tauu) and turbulent heat fluxes (hfls, hfss)." type: "primary" - - slug: "obs4mips.CERES-EBAF-4-2" - description: "CERES Energy Balanced and Filled v4.2 - Surface and TOA radiation fluxes (hfls, hfss, rlds, rlus, rsds, rsus)" + - slug: "obs4ref.CERES-EBAF-4-2" + source: "obs4ref" + description: "CERES Energy Balanced and Filled v4.2. Supplies surface radiation (rlds, rlus, rsds, rsus)." type: "primary" display_name: "ENSO Processes" description: >- @@ -80,8 +77,9 @@ pmp/enso_proc: # Extratropical Modes of Variability (Sea Surface Temperature modes) pmp/extratropical-modes-of-variability-pdo: reference_datasets: - - slug: "obs4mips.HadISST-1-1" - description: "Hadley Centre Sea Ice and SST v1.1 - SST for Pacific Decadal Oscillation" + - slug: "obs4ref.HadISST-1-1" + source: "obs4ref" + description: "Hadley Centre Sea Ice and Sea Surface Temperature v1.1. Supplies ts." type: "primary" display_name: "Pacific Decadal Oscillation (PDO)" description: >- @@ -91,8 +89,9 @@ pmp/extratropical-modes-of-variability-pdo: pmp/extratropical-modes-of-variability-npgo: reference_datasets: - - slug: "obs4mips.HadISST-1-1" - description: "Hadley Centre Sea Ice and SST v1.1 - SST for North Pacific Gyre Oscillation" + - slug: "obs4ref.HadISST-1-1" + source: "obs4ref" + description: "Hadley Centre Sea Ice and Sea Surface Temperature v1.1. Supplies ts." type: "primary" display_name: "North Pacific Gyre Oscillation (NPGO)" description: >- @@ -100,22 +99,12 @@ pmp/extratropical-modes-of-variability-npgo: which tracks changes in the strength of the North Pacific subtropical and subpolar gyres. tags: ["ocean", "variability", "pacific"] -pmp/extratropical-modes-of-variability-amo: - reference_datasets: - - slug: "obs4mips.HadISST-1-1" - description: "Hadley Centre Sea Ice and SST v1.1 - SST for Atlantic Multidecadal Oscillation" - type: "primary" - display_name: "Atlantic Multidecadal Oscillation (AMO)" - description: >- - Calculate the extratropical modes of variability for the Atlantic Multidecadal Oscillation (AMO), - a coherent pattern of variability in North Atlantic SSTs with a period of 60-80 years. - tags: ["ocean", "variability", "atlantic", "decadal"] - # Extratropical Modes of Variability (Sea Level Pressure modes) pmp/extratropical-modes-of-variability-nao: reference_datasets: - - slug: "obs4mips.20CR" - description: "20th Century Reanalysis - Sea level pressure for North Atlantic Oscillation" + - slug: "obs4mips.20CR-V2" + source: "obs4mips" + description: "NOAA 20th Century Reanalysis v2. Supplies psl." type: "primary" display_name: "North Atlantic Oscillation (NAO)" description: >- @@ -125,8 +114,9 @@ pmp/extratropical-modes-of-variability-nao: pmp/extratropical-modes-of-variability-nam: reference_datasets: - - slug: "obs4mips.20CR" - description: "20th Century Reanalysis - Sea level pressure for Northern Annular Mode" + - slug: "obs4mips.20CR-V2" + source: "obs4mips" + description: "NOAA 20th Century Reanalysis v2. Supplies psl." type: "primary" display_name: "Northern Annular Mode (NAM)" description: >- @@ -136,8 +126,9 @@ pmp/extratropical-modes-of-variability-nam: pmp/extratropical-modes-of-variability-pna: reference_datasets: - - slug: "obs4mips.20CR" - description: "20th Century Reanalysis - Sea level pressure for Pacific North American Pattern" + - slug: "obs4mips.20CR-V2" + source: "obs4mips" + description: "NOAA 20th Century Reanalysis v2. Supplies psl." type: "primary" display_name: "Pacific North American Pattern (PNA)" description: >- @@ -147,8 +138,9 @@ pmp/extratropical-modes-of-variability-pna: pmp/extratropical-modes-of-variability-npo: reference_datasets: - - slug: "obs4mips.20CR" - description: "20th Century Reanalysis - Sea level pressure for North Pacific Oscillation" + - slug: "obs4mips.20CR-V2" + source: "obs4mips" + description: "NOAA 20th Century Reanalysis v2. Supplies psl." type: "primary" display_name: "North Pacific Oscillation (NPO)" description: >- @@ -158,8 +150,9 @@ pmp/extratropical-modes-of-variability-npo: pmp/extratropical-modes-of-variability-sam: reference_datasets: - - slug: "obs4mips.20CR" - description: "20th Century Reanalysis - Sea level pressure for Southern Annular Mode" + - slug: "obs4mips.20CR-V2" + source: "obs4mips" + description: "NOAA 20th Century Reanalysis v2. Supplies psl." type: "primary" display_name: "Southern Annular Mode (SAM)" description: >- diff --git a/backend/tests/test_core/test_diagnostic_metadata.py b/backend/tests/test_core/test_diagnostic_metadata.py index 53b448a5..12b93fca 100644 --- a/backend/tests/test_core/test_diagnostic_metadata.py +++ b/backend/tests/test_core/test_diagnostic_metadata.py @@ -290,3 +290,73 @@ def test_optional_fields(self, tmp_path: Path): assert full.tags == ["tag1", "tag2"] assert full.reference_datasets is not None assert full.reference_datasets[0].description == "A test dataset" + + def test_source_is_optional_and_validated(self, tmp_path: Path): + """Test that the reference dataset source is parsed and constrained to known values.""" + yaml_content = { + "with/source": { + "reference_datasets": [ + {"slug": "obs4mips.HadISST-1-1", "type": "primary", "source": "obs4ref"}, + {"slug": "obs4mips.ERA-5", "type": "primary", "source": "obs4mips"}, + ], + }, + "without/source": { + "reference_datasets": [{"slug": "obs4mips.ERA-5", "type": "primary"}], + }, + "bad/source": { + "reference_datasets": [ + {"slug": "obs4mips.ERA-5", "type": "primary", "source": "not-a-collection"} + ], + }, + } + + yaml_path = tmp_path / "sources.yaml" + with open(yaml_path, "w") as f: + yaml.dump(yaml_content, f) + + result = load_diagnostic_metadata(yaml_path) + + with_source = result["with/source"].reference_datasets + assert with_source is not None + assert [rd.source for rd in with_source] == ["obs4ref", "obs4mips"] + + without_source = result["without/source"].reference_datasets + assert without_source is not None + assert without_source[0].source is None + + # An unknown source fails validation, so the entry is skipped rather than served. + assert "bad/source" not in result + + +class TestStaticDiagnosticMetadata: + """Test the metadata files that ship with the backend.""" + + def test_every_reference_dataset_declares_a_source(self): + """Test that each shipped reference dataset says where its data comes from.""" + metadata = load_diagnostic_metadata(Path(__file__).parents[2] / "static" / "diagnostics") + + assert metadata + + missing = [ + (key, rd.slug) + for key, entry in metadata.items() + for rd in entry.reference_datasets or [] + if rd.source is None + ] + assert missing == [] + + def test_slug_prefix_agrees_with_the_source(self): + """Test that the name a reader sees says the same thing as the structured source.""" + metadata = load_diagnostic_metadata(Path(__file__).parents[2] / "static" / "diagnostics") + + # The datasets named inside a recipe keep the provider's prefix rather than "recipe". + prefix_for_source = {"recipe": "esmvaltool"} + + mismatched = [ + (key, rd.slug, rd.source) + for key, entry in metadata.items() + for rd in entry.reference_datasets or [] + if rd.source is not None + and rd.slug.partition(".")[0] != prefix_for_source.get(rd.source, rd.source) + ] + assert mismatched == [] diff --git a/changelog/74.improvement.md b/changelog/74.improvement.md new file mode 100644 index 00000000..b1566da3 --- /dev/null +++ b/changelog/74.improvement.md @@ -0,0 +1,6 @@ +Updates the diagnostic reference dataset metadata to match the datasets the REF providers actually select, and separates published obs4MIPs data from our pre-release obs4REF data. + +- Names each dataset by who supplies it, so a dataset required as `obs4mips` but served pre-release now reads `obs4ref.HadISST-1-1`. A new `source` field carries the same thing in a structured form for API consumers. +- Corrects the source ids to match the data requirements, so ILAMB and PMP datasets are labelled from the providers rather than from a mix of guesses. +- Adds the five ozone diagnostics, and drops `pmp/enso_perf` and the AMO mode, which the providers no longer register. +- Fixes the ILAMB `emp-gleamgpcp2.3` key, which never matched the diagnostic slug. diff --git a/frontend/src/client/types.gen.ts b/frontend/src/client/types.gen.ts index b2819045..8b9c2c16 100644 --- a/frontend/src/client/types.gen.ts +++ b/frontend/src/client/types.gen.ts @@ -995,7 +995,7 @@ export type ReferenceDatasetLink = { /** * Slug * - * Unique identifier for the dataset(e.g., 'obs4mips.CERES-EBAF.v4.2') + * Unique identifier for the dataset, `.`. The prefix names who supplies the data rather than the source type the requirement asks for, so a dataset required as obs4mips but served pre-release reads 'obs4ref.HadISST-1-1' */ slug: string; /** @@ -1004,6 +1004,18 @@ export type ReferenceDatasetLink = { * Description of how this dataset is used in the diagnostic */ description?: string | null; + /** + * Source + * + * Where the data comes from, which is not the same as its source type: + * - 'obs4mips': published on ESGF obs4MIPs + * - 'obs4ref': pre-release reference data served by the REF, not yet on obs4MIPs + * - 'pmp-climatology': the PMP climatology registry + * - 'esmvaltool-reference': the ESMValTool reference registry + * - 'ilamb': the ILAMB registry + * - 'recipe': named inside the provider's recipe rather than ingested by the REF + */ + source?: 'obs4mips' | 'obs4ref' | 'pmp-climatology' | 'esmvaltool-reference' | 'ilamb' | 'recipe' | null; /** * Type * diff --git a/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx b/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx index a85225de..8e1014d6 100644 --- a/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx +++ b/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx @@ -293,7 +293,9 @@ const DiagnosticInfoLayout = () => { Observational or reference datasets that this diagnostic uses for comparison. Primary references are essential for the diagnostic to run, while secondary references - provide additional context. + provide additional context. The dataset name says where + the data comes from: obs4MIPs data is published, obs4REF + data is pre-release.

@@ -302,14 +304,6 @@ const DiagnosticInfoLayout = () => { {data.reference_datasets.map((ref: ReferenceDatasetLink) => (
- - {ref.type} -
{ref.slug} @@ -320,6 +314,13 @@ const DiagnosticInfoLayout = () => {

)}
+ + {ref.type} +
))} From ca0c3333c2832af706bf88c07a76b3271ca5b0e1 Mon Sep 17 00:00:00 2001 From: Jared Lewis Date: Wed, 2 Sep 2026 18:52:44 +1000 Subject: [PATCH 2/6] fix: make the Biome pre-commit hooks actually work The Biome hooks passed staged filenames to `bash -lc "..."`, so they landed as positional arguments to bash rather than as arguments to Biome. Biome never saw them and checked the whole `frontend/` tree instead. That pulled in `frontend/public/favicon.svg`, which pre-commit itself excludes, so `biome-lint` failed on every commit regardless of what changed. - Collapses the two hooks into one `biome-check`, because `check --write` already covers format and lint. - Sets `pass_filenames: false`, which is what the hook was doing anyway. - Runs the pinned `frontend/node_modules/.bin` binaries instead of `npx --yes`, so Biome and tsc match the versions in `package.json` rather than whatever the registry serves. - Ignores `public/` in `biome.json` to match the pre-commit exclude, and bumps the schema to the installed 2.5.11. --- .pre-commit-config.yaml | 19 +++++++------------ frontend/biome.json | 3 ++- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 45718f9c..e5e9b9e2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -69,25 +69,20 @@ repos: files: ^backend/ # Frontend: Biome format + lint + # Both hooks use the versions pinned in frontend/package.json, not whatever npx resolves. - repo: local hooks: - - id: biome-format - name: Biome format (write) - entry: bash -lc "cd frontend && npx --yes @biomejs/biome check --write" + - id: biome-check + name: Biome check (write) + entry: bash -c "cd frontend && exec ./node_modules/.bin/biome check --write" language: system - files: ^frontend/.*\.(ts|tsx|js|jsx|json|md|css)$ - pass_filenames: true - - id: biome-lint - name: Biome lint - entry: bash -lc "cd frontend && npx --yes @biomejs/biome check" - language: system - files: ^frontend/.*\.(ts|tsx|js|jsx)$ - pass_filenames: true + files: ^frontend/.*\.(ts|tsx|js|jsx|json|jsonc|md|css)$ + pass_filenames: false # Frontend: TypeScript typecheck - id: typescript-typecheck name: TypeScript typecheck - entry: bash -lc "cd frontend && npx --yes tsc -b --noEmit" + entry: bash -c "cd frontend && exec ./node_modules/.bin/tsc -b --noEmit" language: system pass_filenames: false files: ^frontend/ diff --git a/frontend/biome.json b/frontend/biome.json index b315edfd..775503fc 100644 --- a/frontend/biome.json +++ b/frontend/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.4.10/schema.json", + "$schema": "https://biomejs.dev/schemas/2.5.11/schema.json", "vcs": { "enabled": false, "clientKind": "git", @@ -10,6 +10,7 @@ "includes": [ "**", "!**/dist", + "!**/public", "!**/coverage", "!**/src/client", "!**/*.gen.ts", From d26c1142ff71525faac21f2978be2eafc488f032 Mon Sep 17 00:00:00 2001 From: Jared Lewis Date: Wed, 2 Sep 2026 18:53:36 +1000 Subject: [PATCH 3/6] docs: renumber the changelog fragment to the PR, and note the pre-commit fix --- changelog/{74.improvement.md => 82.improvement.md} | 0 changelog/82.trivial.md | 1 + 2 files changed, 1 insertion(+) rename changelog/{74.improvement.md => 82.improvement.md} (100%) create mode 100644 changelog/82.trivial.md diff --git a/changelog/74.improvement.md b/changelog/82.improvement.md similarity index 100% rename from changelog/74.improvement.md rename to changelog/82.improvement.md diff --git a/changelog/82.trivial.md b/changelog/82.trivial.md new file mode 100644 index 00000000..e313c620 --- /dev/null +++ b/changelog/82.trivial.md @@ -0,0 +1 @@ +Fixes the Biome pre-commit hooks, which passed staged filenames to `bash -lc` rather than to Biome and so checked the whole frontend tree on every commit. The hooks now run the Biome and TypeScript versions pinned in `frontend/package.json`. From 10b8230efdcf4446d6dcb513135a5e4dca251da0 Mon Sep 17 00:00:00 2001 From: Jared Lewis Date: Wed, 2 Sep 2026 19:24:19 +1000 Subject: [PATCH 4/6] docs: tighten the reference dataset source wording --- backend/src/ref_backend/core/diagnostic_metadata.py | 8 +++----- .../diagnostics.$providerSlug.$diagnosticSlug/route.tsx | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/backend/src/ref_backend/core/diagnostic_metadata.py b/backend/src/ref_backend/core/diagnostic_metadata.py index 833cd260..b3eddc64 100644 --- a/backend/src/ref_backend/core/diagnostic_metadata.py +++ b/backend/src/ref_backend/core/diagnostic_metadata.py @@ -26,12 +26,10 @@ "recipe", ] """ -Where a reference dataset comes from. +Who supplies a reference dataset, which the source type in the data requirement does not say. -The source type alone does not say this. Most of the datasets a diagnostic requires as -``obs4mips`` are served by the REF's own obs4REF collection ahead of publication, so the -distinction between officially published data and pre-release data has to be recorded here. -This mirrors the prefix on ``ReferenceDatasetLink.slug``. +Most datasets required as ``obs4mips`` are served pre-release from obs4REF, so published and +pre-release data have to be distinguishable. """ diff --git a/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx b/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx index 8e1014d6..7603885b 100644 --- a/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx +++ b/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx @@ -294,8 +294,8 @@ const DiagnosticInfoLayout = () => { uses for comparison. Primary references are essential for the diagnostic to run, while secondary references provide additional context. The dataset name says where - the data comes from: obs4MIPs data is published, obs4REF - data is pre-release. + the data comes from. obs4MIPs data is published, while + obs4REF data is pre-release.

From d549245831ffc72cc8596d996b5ece9038f22bc2 Mon Sep 17 00:00:00 2001 From: Jared Lewis Date: Wed, 2 Sep 2026 20:17:29 +1000 Subject: [PATCH 5/6] refactor: rename the reference dataset `source` field to `source_type` Uses the field's full name, which lines it up with the `source_type` already used elsewhere in the API so the two can be merged later. --- .../ref_backend/core/diagnostic_metadata.py | 15 ++-- backend/static/diagnostics/esmvaltool.yaml | 72 +++++++++---------- backend/static/diagnostics/ilamb.yaml | 34 ++++----- backend/static/diagnostics/pmp.yaml | 36 +++++----- .../test_core/test_diagnostic_metadata.py | 40 +++++------ changelog/82.improvement.md | 2 +- frontend/src/client/types.gen.ts | 6 +- 7 files changed, 103 insertions(+), 102 deletions(-) diff --git a/backend/src/ref_backend/core/diagnostic_metadata.py b/backend/src/ref_backend/core/diagnostic_metadata.py index b3eddc64..89e52835 100644 --- a/backend/src/ref_backend/core/diagnostic_metadata.py +++ b/backend/src/ref_backend/core/diagnostic_metadata.py @@ -17,7 +17,7 @@ from loguru import logger from pydantic import BaseModel, Field -ReferenceDatasetSource = Literal[ +ReferenceDatasetSourceType = Literal[ "obs4mips", "obs4ref", "pmp-climatology", @@ -26,10 +26,10 @@ "recipe", ] """ -Who supplies a reference dataset, which the source type in the data requirement does not say. +The source type of the data actually supplied for a reference dataset. -Most datasets required as ``obs4mips`` are served pre-release from obs4REF, so published and -pre-release data have to be distinguishable. +A diagnostic can require ``obs4mips`` and be served the REF's pre-release ``obs4ref`` copy, so what +is supplied has to be recorded separately from what the requirement asks for. """ @@ -52,10 +52,11 @@ class ReferenceDatasetLink(BaseModel): description: str | None = Field( None, description="Description of how this dataset is used in the diagnostic" ) - source: ReferenceDatasetSource | None = Field( + source_type: ReferenceDatasetSourceType | None = Field( None, description=( - "Where the data comes from, which is not the same as its source type:\n" + "The source type of the data actually supplied, which is not always the one the " + "requirement asks for:\n" "- 'obs4mips': published on ESGF obs4MIPs\n" "- 'obs4ref': pre-release reference data served by the REF, not yet on obs4MIPs\n" "- 'pmp-climatology': the PMP climatology registry\n" @@ -156,7 +157,7 @@ def load_diagnostic_metadata(path: Path) -> dict[str, DiagnosticMetadata]: pmp/annual-cycle: reference_datasets: - slug: "obs4mips.CERES-EBAF-4-2-1" - source: "obs4mips" + source_type: "obs4mips" description: "CERES Energy Balanced and Filled" type: "primary" display_name: "Annual Cycle Analysis" diff --git a/backend/static/diagnostics/esmvaltool.yaml b/backend/static/diagnostics/esmvaltool.yaml index 4a6163f9..b387176f 100644 --- a/backend/static/diagnostics/esmvaltool.yaml +++ b/backend/static/diagnostics/esmvaltool.yaml @@ -2,14 +2,14 @@ # # Reference datasets and display metadata for ESMValTool diagnostics. # -# `slug` is `.`, and `source` says the same thing in a structured field. +# `slug` is `.`, and `source_type` says the same thing in a structured field. # The prefix names who supplies the data, not the source type the requirement asks for, so a # dataset required as `obs4mips` but served pre-release reads `obs4ref.HadISST-1-1`. esmvaltool/cloud-radiative-effects: reference_datasets: - slug: "obs4mips.CERES-EBAF-4-2-1" - source: "obs4mips" + source_type: "obs4mips" description: "CERES Energy Balanced and Filled v4.2.1. Supplies rlut, rlutcs, rsut and rsutcs." type: "primary" display_name: "Cloud Radiative Effects" @@ -21,7 +21,7 @@ esmvaltool/cloud-radiative-effects: esmvaltool/cloud-scatterplots-cli-ta: reference_datasets: - slug: "esmvaltool.CALIPSO-ICECLOUD" - source: "recipe" + source_type: "recipe" description: "CALIPSO ice cloud properties. Supplies cli, named in the recipe." type: "secondary" display_name: "Cloud-Temperature Scatterplots (cli vs ta)" @@ -34,11 +34,11 @@ esmvaltool/cloud-scatterplots-cli-ta: esmvaltool/cloud-scatterplots-clivi-lwcre: reference_datasets: - slug: "esmvaltool.CERES-EBAF" - source: "recipe" + source_type: "recipe" description: "CERES Energy Balanced and Filled. Supplies rlut and rlutcs (lwcre derived), named in the recipe." type: "primary" - slug: "esmvaltool.ESACCI-CLOUD" - source: "recipe" + source_type: "recipe" description: "ESA CCI cloud properties. Supplies clivi, named in the recipe." type: "secondary" display_name: "Cloud-Radiation Scatterplots (clivi vs lwcre)" @@ -48,11 +48,11 @@ esmvaltool/cloud-scatterplots-clivi-lwcre: esmvaltool/cloud-scatterplots-clt-swcre: reference_datasets: - slug: "esmvaltool.CERES-EBAF" - source: "recipe" + source_type: "recipe" description: "CERES Energy Balanced and Filled. Supplies rsut and rsutcs (swcre derived), named in the recipe." type: "primary" - slug: "esmvaltool.ESACCI-CLOUD" - source: "recipe" + source_type: "recipe" description: "ESA CCI cloud properties. Supplies clt, named in the recipe." type: "secondary" display_name: "Cloud-Radiation Scatterplots (clt vs swcre)" @@ -62,15 +62,15 @@ esmvaltool/cloud-scatterplots-clt-swcre: esmvaltool/cloud-scatterplots-clwvi-pr: reference_datasets: - slug: "esmvaltool.GPCP-V2.3" - source: "recipe" + source_type: "recipe" description: "GPCP v2.3. Supplies pr, named in the recipe." type: "secondary" - slug: "esmvaltool.ESACCI-CLOUD" - source: "recipe" + source_type: "recipe" description: "ESA CCI cloud properties. Supplies clwvi, named in the recipe." type: "secondary" - slug: "esmvaltool.CERES-EBAF" - source: "recipe" + source_type: "recipe" description: "CERES Energy Balanced and Filled. Supplies the radiation fields, named in the recipe." type: "primary" display_name: "Cloud-Precipitation Scatterplots (clwvi vs pr)" @@ -80,23 +80,23 @@ esmvaltool/cloud-scatterplots-clwvi-pr: esmvaltool/cloud-scatterplots-reference: reference_datasets: - slug: "obs4mips.ERA-5" - source: "obs4mips" + source_type: "obs4mips" description: "ERA5 reanalysis. Supplies ta over 2007 to 2014." type: "primary" - slug: "esmvaltool.CERES-EBAF" - source: "recipe" + source_type: "recipe" description: "CERES Energy Balanced and Filled. Supplies the radiation fields, named in the recipe." type: "primary" - slug: "esmvaltool.CALIPSO-ICECLOUD" - source: "recipe" + source_type: "recipe" description: "CALIPSO ice cloud properties. Supplies cli, named in the recipe." type: "secondary" - slug: "esmvaltool.ESACCI-CLOUD" - source: "recipe" + source_type: "recipe" description: "ESA CCI cloud properties. Supplies clt, clwvi and clivi, named in the recipe." type: "secondary" - slug: "esmvaltool.GPCP-V2.3" - source: "recipe" + source_type: "recipe" description: "GPCP v2.3. Supplies pr, named in the recipe because it cannot be ingested (climate-ref issue 260)." type: "secondary" display_name: "Cloud Scatterplots for Reference dataset" @@ -108,11 +108,11 @@ esmvaltool/cloud-scatterplots-reference: esmvaltool/enso-basic-climatology: reference_datasets: - slug: "esmvaltool.GPCP-V2.3" - source: "recipe" + source_type: "recipe" description: "GPCP v2.3. Supplies pr, named in the recipe." type: "secondary" - slug: "esmvaltool.TROPFLUX" - source: "recipe" + source_type: "recipe" description: "TropFlux. Supplies tos and tauu, named in the recipe." type: "secondary" display_name: "ENSO Basic Climatology" @@ -124,7 +124,7 @@ esmvaltool/enso-basic-climatology: esmvaltool/enso-characteristics: reference_datasets: - slug: "esmvaltool.TROPFLUX" - source: "recipe" + source_type: "recipe" description: "TropFlux. Supplies tos, named in the recipe." type: "primary" display_name: "ENSO Characteristics" @@ -136,7 +136,7 @@ esmvaltool/enso-characteristics: esmvaltool/ozone-annual-cycle: reference_datasets: - slug: "obs4mips.C3S-GTO-ECV-9-0" - source: "obs4mips" + source_type: "obs4mips" description: "C3S GTO-ECV total column ozone v9.0. Supplies toz." type: "primary" display_name: "Ozone Annual Cycle" @@ -146,7 +146,7 @@ esmvaltool/ozone-annual-cycle: esmvaltool/ozone-lat-time: reference_datasets: - slug: "obs4mips.C3S-GTO-ECV-9-0" - source: "obs4mips" + source_type: "obs4mips" description: "C3S GTO-ECV total column ozone v9.0. Supplies toz." type: "primary" display_name: "Ozone Latitude vs Time" @@ -156,7 +156,7 @@ esmvaltool/ozone-lat-time: esmvaltool/ozone-nh-mar: reference_datasets: - slug: "obs4mips.C3S-GTO-ECV-9-0" - source: "obs4mips" + source_type: "obs4mips" description: "C3S GTO-ECV total column ozone v9.0. Supplies toz." type: "primary" display_name: "Ozone Northern Polar Cap (March)" @@ -166,7 +166,7 @@ esmvaltool/ozone-nh-mar: esmvaltool/ozone-sh-oct: reference_datasets: - slug: "obs4mips.C3S-GTO-ECV-9-0" - source: "obs4mips" + source_type: "obs4mips" description: "C3S GTO-ECV total column ozone v9.0. Supplies toz." type: "primary" display_name: "Ozone Southern Polar Cap (October)" @@ -221,19 +221,19 @@ esmvaltool/zero-emission-commitment: esmvaltool/regional-historical-annual-cycle: reference_datasets: - slug: "obs4mips.ERA-5" - source: "obs4mips" + source_type: "obs4mips" description: "ERA5 reanalysis. Supplies psl and ua." type: "primary" - slug: "esmvaltool.HadCRUT5" - source: "recipe" + source_type: "recipe" description: "HadCRUT5 v5.0.1.0 analysis. Supplies tas, named in the recipe." type: "secondary" - slug: "esmvaltool.GPCP-V2.3" - source: "recipe" + source_type: "recipe" description: "GPCP v2.3. Supplies pr, named in the recipe because it cannot be ingested (climate-ref issue 260)." type: "secondary" - slug: "esmvaltool.ERA5-native6" - source: "recipe" + source_type: "recipe" description: "ERA5 native6. Supplies hus, which is not on obs4MIPs." type: "secondary" display_name: "Regional Historical Annual Cycle" @@ -247,19 +247,19 @@ esmvaltool/regional-historical-annual-cycle: esmvaltool/regional-historical-timeseries: reference_datasets: - slug: "obs4mips.ERA-5" - source: "obs4mips" + source_type: "obs4mips" description: "ERA5 reanalysis. Supplies psl and ua." type: "primary" - slug: "esmvaltool.HadCRUT5" - source: "recipe" + source_type: "recipe" description: "HadCRUT5 v5.0.1.0 analysis. Supplies tas, named in the recipe." type: "secondary" - slug: "esmvaltool.GPCP-V2.3" - source: "recipe" + source_type: "recipe" description: "GPCP v2.3. Supplies pr, named in the recipe because it cannot be ingested (climate-ref issue 260)." type: "secondary" - slug: "esmvaltool.ERA5-native6" - source: "recipe" + source_type: "recipe" description: "ERA5 native6. Supplies hus, which is not on obs4MIPs." type: "secondary" display_name: "Regional Historical Timeseries" @@ -273,19 +273,19 @@ esmvaltool/regional-historical-timeseries: esmvaltool/regional-historical-trend: reference_datasets: - slug: "obs4mips.ERA-5" - source: "obs4mips" + source_type: "obs4mips" description: "ERA5 reanalysis. Supplies psl, tas and ua." type: "primary" - slug: "esmvaltool.HadCRUT5" - source: "recipe" + source_type: "recipe" description: "HadCRUT5 v5.0.1.0 analysis. Supplies tas, named in the recipe." type: "secondary" - slug: "esmvaltool.GPCP-V2.3" - source: "recipe" + source_type: "recipe" description: "GPCP v2.3. Supplies pr, named in the recipe because it cannot be ingested (climate-ref issue 260)." type: "secondary" - slug: "esmvaltool.ERA5-native6" - source: "recipe" + source_type: "recipe" description: "ERA5 native6. Supplies hus and pr, named in the recipe." type: "secondary" display_name: "Regional Historical Trends" @@ -299,11 +299,11 @@ esmvaltool/regional-historical-trend: esmvaltool/sea-ice-area-basic: reference_datasets: - slug: "esmvaltool-reference.OSI-450-nh" - source: "esmvaltool-reference" + source_type: "esmvaltool-reference" description: "OSI-450 v3 Northern Hemisphere. Supplies sic and areacello." type: "primary" - slug: "esmvaltool-reference.OSI-450-sh" - source: "esmvaltool-reference" + source_type: "esmvaltool-reference" description: "OSI-450 v3 Southern Hemisphere. Supplies sic and areacello." type: "primary" display_name: "Arctic and Antarctic Sea Ice Area Seasonal Cycle" diff --git a/backend/static/diagnostics/ilamb.yaml b/backend/static/diagnostics/ilamb.yaml index cecb4720..ea4ec878 100644 --- a/backend/static/diagnostics/ilamb.yaml +++ b/backend/static/diagnostics/ilamb.yaml @@ -3,7 +3,7 @@ # Reference datasets and display metadata for ILAMB (International Land Model # Benchmarking) and IOMB (International Ocean Model Benchmarking) diagnostics. # -# `slug` is `.`, and `source` says the same thing in a structured field. +# `slug` is `.`, and `source_type` says the same thing in a structured field. # The prefix names who supplies the data, not the source type the requirement asks for, so a # dataset required as `obs4mips` but served pre-release reads `obs4ref.HadISST-1-1`. @@ -12,15 +12,15 @@ ilamb/gpp-wecann: reference_datasets: - slug: "obs4ref.WECANN-1-0" - source: "obs4ref" + source_type: "obs4ref" description: "WECANN v1.0. Supplies gpp." type: "primary" - slug: "obs4ref.GPCP-2-3" - source: "obs4ref" + source_type: "obs4ref" description: "GPCP v2.3. Supplies pr for the relationship analysis." type: "secondary" - slug: "ilamb.CRU4.02" - source: "ilamb" + source_type: "ilamb" description: "CRU TS v4.02. Supplies tas for the relationship analysis." type: "secondary" display_name: "Gross Primary Productivity (WECANN)" @@ -30,7 +30,7 @@ ilamb/gpp-wecann: ilamb/gpp-fluxnet2015: reference_datasets: - slug: "obs4ref.FLUXNET2015-1-0" - source: "obs4ref" + source_type: "obs4ref" description: "FLUXNET2015 v1.0 tower sites. Supplies gpp, referenced by registry key rather than ingested facets." type: "primary" display_name: "Gross Primary Productivity (FLUXNET2015)" @@ -40,7 +40,7 @@ ilamb/gpp-fluxnet2015: ilamb/mrro-lora: reference_datasets: - slug: "obs4ref.LORA-1-0" - source: "obs4ref" + source_type: "obs4ref" description: "LORA v1.0. Supplies mrro." type: "primary" display_name: "Runoff (LORA)" @@ -50,7 +50,7 @@ ilamb/mrro-lora: ilamb/mrsos-wangmao: reference_datasets: - slug: "ilamb.WangMao" - source: "ilamb" + source_type: "ilamb" description: "Wang and Mao soil moisture. Supplies mrsol, converted to a surface volumetric fraction." type: "primary" display_name: "Surface Soil Moisture (WangMao)" @@ -60,7 +60,7 @@ ilamb/mrsos-wangmao: ilamb/csoil-hwsd2: reference_datasets: - slug: "obs4ref.HWSD-2-0" - source: "obs4ref" + source_type: "obs4ref" description: "Harmonized World Soil Database v2.0. Supplies cSoil." type: "primary" display_name: "Soil Carbon (HWSD2)" @@ -70,7 +70,7 @@ ilamb/csoil-hwsd2: ilamb/lai-avh15c1: reference_datasets: - slug: "obs4mips.NOAA-NCEI-LAI-AVHRR-5-0" - source: "obs4mips" + source_type: "obs4mips" description: "NOAA NCEI AVHRR leaf area index v5.0. Supplies lai, coarsened to a common grid before comparison." type: "primary" display_name: "Leaf Area Index (AVH15C1)" @@ -80,7 +80,7 @@ ilamb/lai-avh15c1: ilamb/nbp-hoffman: reference_datasets: - slug: "obs4ref.Hoffman-1-0" - source: "obs4ref" + source_type: "obs4ref" description: "Hoffman v1.0. Supplies nbp as a global mean." type: "primary" display_name: "Net Biome Productivity (Hoffman)" @@ -90,7 +90,7 @@ ilamb/nbp-hoffman: ilamb/snc-esacci: reference_datasets: - slug: "obs4ref.CCI-CryoClim-FSC-1" - source: "obs4ref" + source_type: "obs4ref" description: "ESA CCI CryoClim fractional snow cover v1. Supplies snc." type: "primary" display_name: "Snow Cover (ESA CCI)" @@ -100,7 +100,7 @@ ilamb/snc-esacci: ilamb/burntfractionall-gfed: reference_datasets: - slug: "obs4ref.GFED-5-0" - source: "obs4ref" + source_type: "obs4ref" description: "Global Fire Emissions Database v5.0. Supplies burntFractionAll." type: "primary" display_name: "Burnt Fraction (GFED)" @@ -110,11 +110,11 @@ ilamb/burntfractionall-gfed: ilamb/emp-gleamgpcp2.3: reference_datasets: - slug: "ilamb.GLEAMv3.3a" - source: "ilamb" + source_type: "ilamb" description: "GLEAM v3.3a. Supplies evapotranspiration (et)." type: "primary" - slug: "obs4ref.GPCP-2-3" - source: "obs4ref" + source_type: "obs4ref" description: "GPCP v2.3. Supplies pr." type: "primary" display_name: "Evaporation minus Precipitation (GLEAM/GPCP)" @@ -126,7 +126,7 @@ ilamb/emp-gleamgpcp2.3: ilamb/thetao-woa2023-surface: reference_datasets: - slug: "obs4ref.WOA-23" - source: "obs4ref" + source_type: "obs4ref" description: "World Ocean Atlas 2023 monthly climatology (2005 to 2022). Supplies thetao, taken at the surface." type: "primary" display_name: "Sea Water Temperature (WOA2023 Surface)" @@ -136,7 +136,7 @@ ilamb/thetao-woa2023-surface: ilamb/so-woa2023-surface: reference_datasets: - slug: "obs4ref.WOA-23" - source: "obs4ref" + source_type: "obs4ref" description: "World Ocean Atlas 2023 monthly climatology (2005 to 2022). Supplies so, taken at the surface." type: "primary" display_name: "Sea Water Salinity (WOA2023 Surface)" @@ -146,7 +146,7 @@ ilamb/so-woa2023-surface: ilamb/amoc-rapid: reference_datasets: - slug: "obs4ref.RAPID-2023-1a" - source: "obs4ref" + source_type: "obs4ref" description: "RAPID array 2023 release 1a. Supplies msftmz, transformed into the RAPID AMOC index." type: "primary" display_name: "Atlantic Meridional Overturning Circulation (RAPID)" diff --git a/backend/static/diagnostics/pmp.yaml b/backend/static/diagnostics/pmp.yaml index 789dd16d..afb9d071 100644 --- a/backend/static/diagnostics/pmp.yaml +++ b/backend/static/diagnostics/pmp.yaml @@ -2,22 +2,22 @@ # # Reference datasets and display metadata for PMP (PCMDI Metrics Package) diagnostics. # -# `slug` is `.`, and `source` says the same thing in a structured field. +# `slug` is `.`, and `source_type` says the same thing in a structured field. # The prefix names who supplies the data, not the source type the requirement asks for, so a # dataset required as `obs4mips` but served pre-release reads `obs4ref.HadISST-1-1`. pmp/annual-cycle: reference_datasets: - slug: "pmp-climatology.ERA-5" - source: "pmp-climatology" + source_type: "pmp-climatology" description: "ERA5 reanalysis climatology. Supplies ts, uas, vas, psl, ta, ua, va and zg." type: "primary" - slug: "pmp-climatology.GPCP-3-3" - source: "pmp-climatology" + source_type: "pmp-climatology" description: "Global Precipitation Climatology Project v3.3 climatology. Supplies pr." type: "primary" - slug: "pmp-climatology.CERES-EBAF-4-2" - source: "pmp-climatology" + source_type: "pmp-climatology" description: "CERES Energy Balanced and Filled v4.2 climatology. Supplies rlds, rlus, rlut, rsds, rsdt, rsus and rsut." type: "primary" display_name: "Annual Cycle Analysis" @@ -31,15 +31,15 @@ pmp/annual-cycle: pmp/enso_tel: reference_datasets: - slug: "obs4ref.GPCP-Monthly-3-2" - source: "obs4ref" + source_type: "obs4ref" description: "Global Precipitation Climatology Project v3.2. Supplies pr." type: "primary" - slug: "obs4ref.HadISST-1-1" - source: "obs4ref" + source_type: "obs4ref" description: "Hadley Centre Sea Ice and Sea Surface Temperature v1.1. Supplies ts." type: "primary" - slug: "obs4ref.TropFlux-1-0" - source: "obs4ref" + source_type: "obs4ref" description: "TropFlux v1.0. Supplies air/sea flux and surface fields over the tropical oceans." type: "primary" display_name: "ENSO Teleconnections" @@ -52,19 +52,19 @@ pmp/enso_tel: pmp/enso_proc: reference_datasets: - slug: "obs4ref.GPCP-Monthly-3-2" - source: "obs4ref" + source_type: "obs4ref" description: "Global Precipitation Climatology Project v3.2. Supplies pr." type: "primary" - slug: "obs4ref.HadISST-1-1" - source: "obs4ref" + source_type: "obs4ref" description: "Hadley Centre Sea Ice and Sea Surface Temperature v1.1. Supplies ts." type: "primary" - slug: "obs4ref.TropFlux-1-0" - source: "obs4ref" + source_type: "obs4ref" description: "TropFlux v1.0. Supplies zonal wind stress (tauu) and turbulent heat fluxes (hfls, hfss)." type: "primary" - slug: "obs4ref.CERES-EBAF-4-2" - source: "obs4ref" + source_type: "obs4ref" description: "CERES Energy Balanced and Filled v4.2. Supplies surface radiation (rlds, rlus, rsds, rsus)." type: "primary" display_name: "ENSO Processes" @@ -78,7 +78,7 @@ pmp/enso_proc: pmp/extratropical-modes-of-variability-pdo: reference_datasets: - slug: "obs4ref.HadISST-1-1" - source: "obs4ref" + source_type: "obs4ref" description: "Hadley Centre Sea Ice and Sea Surface Temperature v1.1. Supplies ts." type: "primary" display_name: "Pacific Decadal Oscillation (PDO)" @@ -90,7 +90,7 @@ pmp/extratropical-modes-of-variability-pdo: pmp/extratropical-modes-of-variability-npgo: reference_datasets: - slug: "obs4ref.HadISST-1-1" - source: "obs4ref" + source_type: "obs4ref" description: "Hadley Centre Sea Ice and Sea Surface Temperature v1.1. Supplies ts." type: "primary" display_name: "North Pacific Gyre Oscillation (NPGO)" @@ -103,7 +103,7 @@ pmp/extratropical-modes-of-variability-npgo: pmp/extratropical-modes-of-variability-nao: reference_datasets: - slug: "obs4mips.20CR-V2" - source: "obs4mips" + source_type: "obs4mips" description: "NOAA 20th Century Reanalysis v2. Supplies psl." type: "primary" display_name: "North Atlantic Oscillation (NAO)" @@ -115,7 +115,7 @@ pmp/extratropical-modes-of-variability-nao: pmp/extratropical-modes-of-variability-nam: reference_datasets: - slug: "obs4mips.20CR-V2" - source: "obs4mips" + source_type: "obs4mips" description: "NOAA 20th Century Reanalysis v2. Supplies psl." type: "primary" display_name: "Northern Annular Mode (NAM)" @@ -127,7 +127,7 @@ pmp/extratropical-modes-of-variability-nam: pmp/extratropical-modes-of-variability-pna: reference_datasets: - slug: "obs4mips.20CR-V2" - source: "obs4mips" + source_type: "obs4mips" description: "NOAA 20th Century Reanalysis v2. Supplies psl." type: "primary" display_name: "Pacific North American Pattern (PNA)" @@ -139,7 +139,7 @@ pmp/extratropical-modes-of-variability-pna: pmp/extratropical-modes-of-variability-npo: reference_datasets: - slug: "obs4mips.20CR-V2" - source: "obs4mips" + source_type: "obs4mips" description: "NOAA 20th Century Reanalysis v2. Supplies psl." type: "primary" display_name: "North Pacific Oscillation (NPO)" @@ -151,7 +151,7 @@ pmp/extratropical-modes-of-variability-npo: pmp/extratropical-modes-of-variability-sam: reference_datasets: - slug: "obs4mips.20CR-V2" - source: "obs4mips" + source_type: "obs4mips" description: "NOAA 20th Century Reanalysis v2. Supplies psl." type: "primary" display_name: "Southern Annular Mode (SAM)" diff --git a/backend/tests/test_core/test_diagnostic_metadata.py b/backend/tests/test_core/test_diagnostic_metadata.py index 12b93fca..a2950cc2 100644 --- a/backend/tests/test_core/test_diagnostic_metadata.py +++ b/backend/tests/test_core/test_diagnostic_metadata.py @@ -291,13 +291,13 @@ def test_optional_fields(self, tmp_path: Path): assert full.reference_datasets is not None assert full.reference_datasets[0].description == "A test dataset" - def test_source_is_optional_and_validated(self, tmp_path: Path): - """Test that the reference dataset source is parsed and constrained to known values.""" + def test_source_type_is_optional_and_validated(self, tmp_path: Path): + """Test that the reference dataset source type is parsed and constrained to known values.""" yaml_content = { "with/source": { "reference_datasets": [ - {"slug": "obs4mips.HadISST-1-1", "type": "primary", "source": "obs4ref"}, - {"slug": "obs4mips.ERA-5", "type": "primary", "source": "obs4mips"}, + {"slug": "obs4mips.HadISST-1-1", "type": "primary", "source_type": "obs4ref"}, + {"slug": "obs4mips.ERA-5", "type": "primary", "source_type": "obs4mips"}, ], }, "without/source": { @@ -305,7 +305,7 @@ def test_source_is_optional_and_validated(self, tmp_path: Path): }, "bad/source": { "reference_datasets": [ - {"slug": "obs4mips.ERA-5", "type": "primary", "source": "not-a-collection"} + {"slug": "obs4mips.ERA-5", "type": "primary", "source_type": "not-a-collection"} ], }, } @@ -316,22 +316,22 @@ def test_source_is_optional_and_validated(self, tmp_path: Path): result = load_diagnostic_metadata(yaml_path) - with_source = result["with/source"].reference_datasets - assert with_source is not None - assert [rd.source for rd in with_source] == ["obs4ref", "obs4mips"] + with_source_type = result["with/source"].reference_datasets + assert with_source_type is not None + assert [rd.source_type for rd in with_source_type] == ["obs4ref", "obs4mips"] - without_source = result["without/source"].reference_datasets - assert without_source is not None - assert without_source[0].source is None + without_source_type = result["without/source"].reference_datasets + assert without_source_type is not None + assert without_source_type[0].source_type is None - # An unknown source fails validation, so the entry is skipped rather than served. + # An unknown source type fails validation, so the entry is skipped rather than served. assert "bad/source" not in result class TestStaticDiagnosticMetadata: """Test the metadata files that ship with the backend.""" - def test_every_reference_dataset_declares_a_source(self): + def test_every_reference_dataset_declares_a_source_type(self): """Test that each shipped reference dataset says where its data comes from.""" metadata = load_diagnostic_metadata(Path(__file__).parents[2] / "static" / "diagnostics") @@ -341,22 +341,22 @@ def test_every_reference_dataset_declares_a_source(self): (key, rd.slug) for key, entry in metadata.items() for rd in entry.reference_datasets or [] - if rd.source is None + if rd.source_type is None ] assert missing == [] - def test_slug_prefix_agrees_with_the_source(self): - """Test that the name a reader sees says the same thing as the structured source.""" + def test_slug_prefix_agrees_with_the_source_type(self): + """Test that the name a reader sees says the same thing as the structured source type.""" metadata = load_diagnostic_metadata(Path(__file__).parents[2] / "static" / "diagnostics") # The datasets named inside a recipe keep the provider's prefix rather than "recipe". - prefix_for_source = {"recipe": "esmvaltool"} + prefix_for_source_type = {"recipe": "esmvaltool"} mismatched = [ - (key, rd.slug, rd.source) + (key, rd.slug, rd.source_type) for key, entry in metadata.items() for rd in entry.reference_datasets or [] - if rd.source is not None - and rd.slug.partition(".")[0] != prefix_for_source.get(rd.source, rd.source) + if rd.source_type is not None + and rd.slug.partition(".")[0] != prefix_for_source_type.get(rd.source_type, rd.source_type) ] assert mismatched == [] diff --git a/changelog/82.improvement.md b/changelog/82.improvement.md index b1566da3..546fa54c 100644 --- a/changelog/82.improvement.md +++ b/changelog/82.improvement.md @@ -1,6 +1,6 @@ Updates the diagnostic reference dataset metadata to match the datasets the REF providers actually select, and separates published obs4MIPs data from our pre-release obs4REF data. -- Names each dataset by who supplies it, so a dataset required as `obs4mips` but served pre-release now reads `obs4ref.HadISST-1-1`. A new `source` field carries the same thing in a structured form for API consumers. +- Names each dataset by who supplies it, so a dataset required as `obs4mips` but served pre-release now reads `obs4ref.HadISST-1-1`. A new `source_type` field carries the same thing in a structured form for API consumers. - Corrects the source ids to match the data requirements, so ILAMB and PMP datasets are labelled from the providers rather than from a mix of guesses. - Adds the five ozone diagnostics, and drops `pmp/enso_perf` and the AMO mode, which the providers no longer register. - Fixes the ILAMB `emp-gleamgpcp2.3` key, which never matched the diagnostic slug. diff --git a/frontend/src/client/types.gen.ts b/frontend/src/client/types.gen.ts index 8b9c2c16..a95a810a 100644 --- a/frontend/src/client/types.gen.ts +++ b/frontend/src/client/types.gen.ts @@ -1005,9 +1005,9 @@ export type ReferenceDatasetLink = { */ description?: string | null; /** - * Source + * Source Type * - * Where the data comes from, which is not the same as its source type: + * The source type of the data actually supplied, which is not always the one the requirement asks for: * - 'obs4mips': published on ESGF obs4MIPs * - 'obs4ref': pre-release reference data served by the REF, not yet on obs4MIPs * - 'pmp-climatology': the PMP climatology registry @@ -1015,7 +1015,7 @@ export type ReferenceDatasetLink = { * - 'ilamb': the ILAMB registry * - 'recipe': named inside the provider's recipe rather than ingested by the REF */ - source?: 'obs4mips' | 'obs4ref' | 'pmp-climatology' | 'esmvaltool-reference' | 'ilamb' | 'recipe' | null; + source_type?: 'obs4mips' | 'obs4ref' | 'pmp-climatology' | 'esmvaltool-reference' | 'ilamb' | 'recipe' | null; /** * Type * From d0d8d56b1b51a95b7a242ea9494fa2101665e07b Mon Sep 17 00:00:00 2001 From: Jared Lewis Date: Wed, 2 Sep 2026 20:28:22 +1000 Subject: [PATCH 6/6] docs: stop repeating pre-release in the reference dataset wording --- backend/src/ref_backend/core/diagnostic_metadata.py | 8 ++++---- backend/static/diagnostics/esmvaltool.yaml | 2 +- backend/static/diagnostics/ilamb.yaml | 2 +- backend/static/diagnostics/pmp.yaml | 2 +- changelog/82.improvement.md | 4 ++-- frontend/src/client/types.gen.ts | 4 ++-- .../diagnostics.$providerSlug.$diagnosticSlug/route.tsx | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/src/ref_backend/core/diagnostic_metadata.py b/backend/src/ref_backend/core/diagnostic_metadata.py index 89e52835..1e881ae8 100644 --- a/backend/src/ref_backend/core/diagnostic_metadata.py +++ b/backend/src/ref_backend/core/diagnostic_metadata.py @@ -28,8 +28,8 @@ """ The source type of the data actually supplied for a reference dataset. -A diagnostic can require ``obs4mips`` and be served the REF's pre-release ``obs4ref`` copy, so what -is supplied has to be recorded separately from what the requirement asks for. +A diagnostic can require ``obs4mips`` and be served the REF's own ``obs4ref`` copy, so what is +supplied has to be recorded separately from what the requirement asks for. """ @@ -46,7 +46,7 @@ class ReferenceDatasetLink(BaseModel): description=( "Unique identifier for the dataset, `.`. The prefix names who " "supplies the data rather than the source type the requirement asks for, so a dataset " - "required as obs4mips but served pre-release reads 'obs4ref.HadISST-1-1'" + "required as obs4mips but supplied from obs4REF reads 'obs4ref.HadISST-1-1'" ), ) description: str | None = Field( @@ -58,7 +58,7 @@ class ReferenceDatasetLink(BaseModel): "The source type of the data actually supplied, which is not always the one the " "requirement asks for:\n" "- 'obs4mips': published on ESGF obs4MIPs\n" - "- 'obs4ref': pre-release reference data served by the REF, not yet on obs4MIPs\n" + "- 'obs4ref': reference data served by the REF, not yet published on obs4MIPs\n" "- 'pmp-climatology': the PMP climatology registry\n" "- 'esmvaltool-reference': the ESMValTool reference registry\n" "- 'ilamb': the ILAMB registry\n" diff --git a/backend/static/diagnostics/esmvaltool.yaml b/backend/static/diagnostics/esmvaltool.yaml index b387176f..edbec4b0 100644 --- a/backend/static/diagnostics/esmvaltool.yaml +++ b/backend/static/diagnostics/esmvaltool.yaml @@ -4,7 +4,7 @@ # # `slug` is `.`, and `source_type` says the same thing in a structured field. # The prefix names who supplies the data, not the source type the requirement asks for, so a -# dataset required as `obs4mips` but served pre-release reads `obs4ref.HadISST-1-1`. +# dataset required as `obs4mips` but supplied from obs4REF reads `obs4ref.HadISST-1-1`. esmvaltool/cloud-radiative-effects: reference_datasets: diff --git a/backend/static/diagnostics/ilamb.yaml b/backend/static/diagnostics/ilamb.yaml index ea4ec878..a65e65f7 100644 --- a/backend/static/diagnostics/ilamb.yaml +++ b/backend/static/diagnostics/ilamb.yaml @@ -5,7 +5,7 @@ # # `slug` is `.`, and `source_type` says the same thing in a structured field. # The prefix names who supplies the data, not the source type the requirement asks for, so a -# dataset required as `obs4mips` but served pre-release reads `obs4ref.HadISST-1-1`. +# dataset required as `obs4mips` but supplied from obs4REF reads `obs4ref.HadISST-1-1`. # Land diagnostics diff --git a/backend/static/diagnostics/pmp.yaml b/backend/static/diagnostics/pmp.yaml index afb9d071..46ef9145 100644 --- a/backend/static/diagnostics/pmp.yaml +++ b/backend/static/diagnostics/pmp.yaml @@ -4,7 +4,7 @@ # # `slug` is `.`, and `source_type` says the same thing in a structured field. # The prefix names who supplies the data, not the source type the requirement asks for, so a -# dataset required as `obs4mips` but served pre-release reads `obs4ref.HadISST-1-1`. +# dataset required as `obs4mips` but supplied from obs4REF reads `obs4ref.HadISST-1-1`. pmp/annual-cycle: reference_datasets: diff --git a/changelog/82.improvement.md b/changelog/82.improvement.md index 546fa54c..e0462aec 100644 --- a/changelog/82.improvement.md +++ b/changelog/82.improvement.md @@ -1,6 +1,6 @@ -Updates the diagnostic reference dataset metadata to match the datasets the REF providers actually select, and separates published obs4MIPs data from our pre-release obs4REF data. +Updates the diagnostic reference dataset metadata to match the datasets the REF providers actually select, and separates published obs4MIPs data from our own obs4REF data. -- Names each dataset by who supplies it, so a dataset required as `obs4mips` but served pre-release now reads `obs4ref.HadISST-1-1`. A new `source_type` field carries the same thing in a structured form for API consumers. +- Names each dataset by who supplies it, so a dataset required as `obs4mips` but supplied from obs4REF now reads `obs4ref.HadISST-1-1`. A new `source_type` field carries the same thing in a structured form for API consumers. - Corrects the source ids to match the data requirements, so ILAMB and PMP datasets are labelled from the providers rather than from a mix of guesses. - Adds the five ozone diagnostics, and drops `pmp/enso_perf` and the AMO mode, which the providers no longer register. - Fixes the ILAMB `emp-gleamgpcp2.3` key, which never matched the diagnostic slug. diff --git a/frontend/src/client/types.gen.ts b/frontend/src/client/types.gen.ts index a95a810a..8e7656ac 100644 --- a/frontend/src/client/types.gen.ts +++ b/frontend/src/client/types.gen.ts @@ -995,7 +995,7 @@ export type ReferenceDatasetLink = { /** * Slug * - * Unique identifier for the dataset, `.`. The prefix names who supplies the data rather than the source type the requirement asks for, so a dataset required as obs4mips but served pre-release reads 'obs4ref.HadISST-1-1' + * Unique identifier for the dataset, `.`. The prefix names who supplies the data rather than the source type the requirement asks for, so a dataset required as obs4mips but supplied from obs4REF reads 'obs4ref.HadISST-1-1' */ slug: string; /** @@ -1009,7 +1009,7 @@ export type ReferenceDatasetLink = { * * The source type of the data actually supplied, which is not always the one the requirement asks for: * - 'obs4mips': published on ESGF obs4MIPs - * - 'obs4ref': pre-release reference data served by the REF, not yet on obs4MIPs + * - 'obs4ref': reference data served by the REF, not yet published on obs4MIPs * - 'pmp-climatology': the PMP climatology registry * - 'esmvaltool-reference': the ESMValTool reference registry * - 'ilamb': the ILAMB registry diff --git a/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx b/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx index 7603885b..a514aae7 100644 --- a/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx +++ b/frontend/src/routes/_app/diagnostics.$providerSlug.$diagnosticSlug/route.tsx @@ -295,7 +295,7 @@ const DiagnosticInfoLayout = () => { for the diagnostic to run, while secondary references provide additional context. The dataset name says where the data comes from. obs4MIPs data is published, while - obs4REF data is pre-release. + obs4REF data is not on obs4MIPs yet.