Skip to content

EnVar microschema · class

Variable Identity

VariableIdentity

The identity and semantics of an environmental exposure variable — what physical quantity is being captured, in what units, and how it binds to community vocabularies. One per record.

18 fields 5 core

URI: envar:class/VariableIdentity

Core Conditionally core Recommended Optional
Core Required for a valid record 5 fields
Variable Namecorerequired

variable_name · range String · cardinality 1

Data tools give each measurement a short nickname, like tmax for maximum temperature. This is that nickname, written down exactly as the tool spells it, so you can go back to the source and find the same measurement again.

Short machine-readable name for the variable, usually the name the upstream tool uses for it (e.g. tmax, tmmx, air.2m). Identity only — not necessarily the column header in the companion data file; that binding lives in DataLayout.value_column (see envar_layout).

Example

tmaxDaymet daily maximum air temperature variable

Covered by — 5 standards
omop_gaiaverifiedfull coverage
where gaia_db/variable_source.variable_name; DeGAUSS/Amadeus emit the short name only as a bare column header (tmax / tmmx)
GAIA carries the variable short name first-class in variable_source.variable_name; the combined stack surfaces it as a named slot.
degaussassertedpartial coverage
where cohort_addresses_geocoded_daymet CSV column header `tmax`
DeGAUSS carries the short name only as the value column header, not as a first-class named slot. Conservative: partial.
amadeusassertedpartial coverage
where gridmet_tmmx.csv column header `tmmx`; thredds_dataset.xml long_name/standard_name = tmmx
Amadeus carries the short name as a column header and in the THREDDS long_name, not as a portable variable-name slot. Conservative: partial.
cherassertedpartial coverage
where table_column_dictionary.column_name (literal column name)
C-HER records each resource's literal column_name, which serves as the variable's machine-readable handle; not a portable sidecar short-name. Conservative: partial.
codataassertedout_of_layer coverage
A tool-specific short name is an instance-layer handle; the CODATA/I-ADOPT conceptual layer names the property canonically, not the upstream tool's nickname.
Why it matters & mappings

This is the handle under which the upstream product knows the variable (Daymet tmax vs gridMET tmmx). Without it the record cannot be traced back to the source product's variable, and a rerun cannot request the same quantity from the tool.

Standard Namecorerequired

standard_name · range Uriorcurie · cardinality 1

Different tools use different nicknames for the same thing, so scientific communities maintain shared official names for physical quantities (like "air_temperature"). Tagging the record with the official name lets computers tell that two datasets measure the same thing, no matter what each dataset called it.

The standard-name identifier for the physical quantity, as a CURIE so the schema privileges no single naming authority. Use a CF Convention Standard Name where one exists (CF:air_temperature, CF:relative_humidity); for health-relevant quantities CF does not define (e.g. Heat Index, WBGT), mint a term in the project registry (ENVAR:heat_index) or reuse an ontology term (ECTO:...). The prefix carries the authority; the slot name does not. Mandatory.

Examples

CF:air_temperatureCF Standard Name for the Daymet daily Tmax scenario

CF:mass_concentration_of_pm2p5_ambient_aerosol_particles_in_airCF Standard Name for the ACAG PM2.5 scenario

Covered by — 5 standards
omop_gaiaverifiedfull coverage
where gaia_db/variable_source.property_id and JSON-LD variableMeasured.propertyID → vocab.nerc.ac.uk/standard_name/air_temperature (NERC/CF mirror)
GAIA is the only stack carrying a real CF standard name, via the hand-authored NERC propertyID in variable_source / JSON-LD.
degaussassertedabsent coverage
DeGAUSS carries no standard-name identifier — the quantity is implicit in the `tmax` column name.
amadeusassertedpartial coverage
where thredds_dataset.xml standard_name = "tmmx" (gridMET shortcode overloaded, not a real CF term)
Amadeus populates a standard_name slot but with the gridMET shortcode rather than a CF term, so a CF lookup fails. Conservative: partial.
cherassertedpartial coverage
where table_column_dictionary.column_tag_id (ontology tag planned §8)
C-HER's column_tag / planned ontology encoding will tag columns to its MORPH-built ontology, but no CF/standard-name binding exists today. Conservative: partial.
codataassertedpartial coverage
where I-ADOPT Object + Property decomposition; DDI-CDI RepresentedVariable (value domain + units)
Naming the physical quantity canonically is exactly CODATA's RepresentedVariable / I-ADOPT layer — its strongest zone — but it names the concept, not this run's specific CURIE.
Why it matters & mappings

This is the cross-agency identifier that makes the variable interoperable: without it, tmax from one product and tmmx from another cannot be recognised by machines as the same physical quantity, so records cannot be pooled or harmonised across studies.

Units (UCUM)corerequired

units_ucum · range String · cardinality 1

UCUM is a compact, machine-readable spelling of the unit — Cel for degrees Celsius, ug/m3 for micrograms per cubic metre — so software can convert °C to °F or check units automatically without guessing what a human-written unit string means.

The unit expressed in UCUM syntax, e.g. Cel for degrees Celsius, K for Kelvin, ug/m3 for PM2.5 mass concentration.

Examples

Celdegrees Celsius (Daymet Tmax)

ug/m3micrograms per cubic metre (PM2.5 mass concentration)

Covered by — 5 standards
omop_gaiaverifiedfull coverage
where gaia_db/variable_source.unit_code (UCUM `CEL`) + unit_text; JSON-LD variableMeasured.unitCode; external_exposure.unit_concept_id 8653
GAIA carries the unit as a first-class UCUM code (CEL) plus the OMOP unit_concept_id.
amadeusverifiedfull coverage
where thredds_dataset.xml units = "K"; gridmet_tmmx.cf_metadata.json mirrors it
Amadeus declares the native unit K in a machine-readable CF metadata slot (though not in UCUM syntax).
degaussassertedabsent coverage
DeGAUSS's `tmax` column has no unit annotation; °C is only a container convention.
cherassertedpartial coverage
where table_column_dictionary.column_unit_id (required for Value-tagged columns)
C-HER requires column_unit on Value-tagged columns, but the unit vocabulary is not asserted to be UCUM. Conservative: partial.
codataassertedpartial coverage
where DDI-CDI RepresentedVariable (value domain + units); I-ADOPT decomposition
Units live at CODATA's RepresentedVariable layer — canonical unit semantics — but not the specific UCUM string of this run's file.
Why it matters & mappings

A number without units is uninterpretable — a value of 35 could be °C or °F, a factor-of-1.8 error in an exposure analysis. UCUM is the machine-readable form that health-data layers (e.g. OMOP's unit_concept_id) align to, so omitting it also blocks automated unit conversion and downstream integration.

See also: https://ucum.org/

Concept Statuscorerequired

concept_status · range ConceptStatusEnum · cardinality 1

A simple status flag saying whether the health-data catalogue already has a code for this measurement, has one in the works, or has nothing yet. It turns a silent gap into an explicit, reportable fact.

Status of this variable's coverage in the target health-data vocabulary (existing / proposed / gap). Makes the vocabulary gap explicit rather than silent. Required.

Example

gapno OMOP concept exists yet for daily Tmax

Allowed values

existing A concept id is available in the target vocabulary proposed A concept submission is in flight gap No concept exists yet and none is yet proposed
Covered by — 5 standards
omop_gaiaassertedabsent coverage
GAIA fills a placeholder exposure_concept_id but carries no existing/proposed/gap status flag saying whether a real OMOP concept exists — an EnVar-novel slot.
degaussassertedabsent coverage
DeGAUSS has no concept binding and so no coverage-status flag.
amadeusassertedabsent coverage
Amadeus has no concept binding and so no coverage-status flag.
cherassertedabsent coverage
C-HER carries no existing/proposed/gap coverage status for a target vocabulary.
codataassertedout_of_layer coverage
A gap-status flag against a target vocabulary is instance/target bookkeeping, outside CODATA's conceptual-alignment layer.
Why it matters & mappings

A downstream system must know whether to expect a concept id. The explicit existing/proposed/gap status makes vocabulary gaps visible and countable rather than silently null — which is what drives vocabulary-extension requests for environmental variables.

Value Data Typecorerequired

value_data_type · range DataTypeEnum · cardinality 1

Says what kind of value to expect: a decimal number that can take any value (like a temperature), a yes/no flag, or a category. Software needs this to know how to read and summarise the data correctly.

The data type of the stored exposure value.

Example

continuous_numeric

Allowed values

continuous_numeric Continuous numeric value (e categorical Categorical value (e binary_flag Binary flag (e count Integer count (e event_marker Date-stamped event (e
Covered by — 5 standards
omop_gaiaverifiedfull coverage
where gaia_catalog meta_etl_*.json qudt:dataType (numeric/float4)
evidence examples/scenarios/standards/omop_gaia_daymet_tmax.yaml (value_data_type)
GAIA registers the attribute's numeric qudt:dataType at dataset-registration time; the EnVar translation carries it first-class as value_data_type.
degaussassertedabsent coverage
DeGAUSS emits a numeric `tmax` column but declares no explicit value data type; the type is implicit in the data.
amadeusassertedabsent coverage
Amadeus emits numeric value_kelvin/value_celsius columns with no explicit value-data-type declaration.
cherassertedpartial coverage
where table_column_dictionary.column_tag (Value) + column_unit (unit present ⇒ numeric)
C-HER's Value tag plus the presence/absence of a column_unit distinguishes numeric from free-text value columns, but not the full continuous/categorical/flag taxonomy. Conservative: partial.
codataassertedpartial coverage
where DDI-CDI RepresentedVariable value domain (numeric vs categorical value domain)
A value domain is exactly what CDI's RepresentedVariable carries, so the numeric/categorical distinction lives at CODATA's represented layer.
Why it matters & mappings

Tells consumers how to parse and analyse the values — continuous numbers, categories, and flags need different statistics and storage. Omitting it forces guessing from the data, which fails on ambiguous cases like 0/1 columns (count, flag, or category?).

Conditionally core Required in specific contexts 2 fields
CF Cell Methodsconditionally core

cf_cell_methods · range String · cardinality 0..1

A "daily temperature" value could be the day's highest reading, its average, or its lowest — very different numbers. This short standard phrase (like "time: maximum") records which one it is, in the exact wording that climate-data software already understands.

CF cell_methods string describing how the value summarises sub-period values, e.g. time: maximum for Tmax, time: mean for daily mean.

Examples

time: maximumdaily maximum (Tmax)

time: meanmean over the aggregation period (e.g. annual-mean PM2.5)

Why it matters & mappings

A daily maximum and a daily mean of the same quantity carry the same standard name and units; only the aggregation statement tells them apart. Keeping the verbatim CF string also enables round-tripping against CF/NetCDF source products and the CF-consistency triple check over standard_name + cf_cell_methods + units_ucum. Conditionally-Core because the slot is CF-specific by design: it is mandatory when standard_name uses the CF: prefix (the context of SPEC.md validation rule 5), while a non-CF product genuinely has no verbatim cell_methods string to preserve — its vocabulary-neutral aggregation semantics live in the required temporal_aggregation_method.

Unit Conversion Formulaconditionally core

unit_conversion_formula · range String · cardinality 0..1

When the original data used different units, this spells out the exact arithmetic that turned them into the numbers in the data file — like showing your work in a calculation, so others can check it.

The conversion from the source's native representation to the values in the companion data file, written out, e.g. Cel = K - 273.15 or K = stored × 0.1 + 220.0; Cel = K - 273.15. Required whenever native_units_ucum is declared.

Example

K = stored * 0.1 + 220.0; Cel = K - 273.15gridMET tmmx unpack-then-convert chain in the Amadeus scenario

Why it matters & mappings

Twin value columns and silent container conversions are how factor-of-1.8 unit errors enter exposure analyses undetected. Once native units are declared, the bridging math is the only record of how the file's values relate to the source's — it is what makes the conversion checkable rather than trusted.

Recommended Strongly encouraged 6 fields
Optional Include when available 5 fields
Display Unitsoptional

units_display · range String · cardinality 0..1

The pretty version of the unit for people to read, like "°C". The machine version (Cel) is stored separately; this one exists purely for showing on screen or in print.

Human-readable unit string for display purposes, e.g. °C.

Example

°C

Why it matters & mappings

Keeps human-facing output (tables, plots, reports) readable without every consumer having to translate UCUM codes; omitting it risks each tool rendering the unit differently or mislabelling axes.

Native Value Scale Factoroptional

native_value_scale_factor · range Float · cardinality 0..1

Big datasets often save space by storing small whole numbers that must be multiplied by a constant to get the real measurement. This is that constant.

CF-style packing multiplier applied when decoding the source's stored integers to physical values (physical = stored × scale_factor + add_offset). Only meaningful alongside native_units_ucum.

Example

0.1gridMET tmmx packs Kelvin as unsigned int16 with scale 0.1

Why it matters & mappings

Anyone re-reading the source grid directly (rather than the companion file) must unpack stored integers with exactly this factor; a wrong or missing factor yields physically plausible but wrong values, the worst kind of error.

Native Value Offsetoptional

native_value_offset · range Float · cardinality 0..1

The second constant in the space-saving trick: after multiplying the stored number, add this to get the real measurement.

CF-style packing offset applied when decoding the source's stored integers to physical values (physical = stored × scale_factor + add_offset). Only meaningful alongside native_units_ucum.

Example

220.0gridMET tmmx packing offset (unpacks to true Kelvin)

Why it matters & mappings

The offset half of the unpacking convention; without it the scale factor alone still decodes to the wrong physical value.

Reason Concept ID Is Missingoptional

target_concept_id_missing_reason · range MissingReasonEnum · cardinality 0..1

When a code is missing, it matters why. This slot records the reason — for example that no such code has been invented yet — so an empty field is not mistaken for a processing mistake.

Reason target_concept_id is null. Distinguishes "no concept yet exists in the target vocabulary" from "the pipeline did not resolve it".

Example

not_provided_by_source

Allowed values

not_provided_by_source Source product does not produce this information available_but_not_extracted Source produces this information but the current pipeline does not surface it upstream_data_not_propagated An upstream tool emitted this information but the current pipeline dropped it... under_investigation We are working on populating this slot not_applicable This slot does not apply to this variable / record
Why it matters & mappings

Without a stated reason, a null target_concept_id is ambiguous: downstream users cannot tell a genuine vocabulary gap from a pipeline that simply failed to look the concept up, and so cannot decide whether to fix the data or request a new concept.

Concept Cross-Referencesoptional

concept_mappings · range Uriorcurie · cardinality * · multivalued

Different scientific communities keep different dictionaries of concepts. This is a list of "also known as" links pointing to the matching entries in those dictionaries, so people searching any of them can still find this measurement.

Cross-references binding this variable to other vocabularies and ontologies, each as a CURIE. One generic list rather than a slot per standard, so adding a vocabulary is a new prefix, not a schema change. Examples: ECTO:0000012 (Environmental Conditions, Treatments and Exposures Ontology — cross-Monarch / cross-CHORDS alignment), ENVO:01000339 (Environment Ontology — material or process exposed to), LOINC:... / SNOMED:... (where the variable has clinical coverage). Note: the primary downstream health-data binding, with its existing / proposed / gap status, stays in the structured target_concept_* slots — this list is for additional, status-free cross-references.

Examples

ECTO:0000012exposure to temperature (ECTO) — one element of the cross-reference list for the Daymet daily Tmax scenario

ENVO:03000049temperature of air (ENVO) — a second element of the same cross-reference list

Why it matters & mappings

Cross-references to ontologies (ECTO, ENVO) and clinical codes (LOINC, SNOMED) let the variable be found and aligned across projects and communities; without them, cross-study harmonisation has to be redone by hand. Enrichment only — not needed to reproduce the value.

Full field reference — every slot, cardinality & inheritance
Field Name Tier Cardinality / Range Description
Variable Name variable_name core 1
String
Short machine-readable name for the variable, usually the name the upstream t...
Variable Label variable_label recommended 0..1
String
Human-readable label, e
Standard Name standard_name core 1
Uriorcurie
The standard-name identifier for the physical quantity, as a CURIE so the sch...
CF Cell Methods cf_cell_methods conditionally core 0..1
String
CF cell_methods string describing how the value summarises sub-period value...
Units (UCUM) units_ucum core 1
String
The unit expressed in UCUM syntax, e
Display Units units_display optional 0..1
String
Human-readable unit string for display purposes, e
Native Units (UCUM) native_units_ucum recommended 0..1
String
UCUM unit of the values as the source product stores them, when that differ...
Native Value Scale Factor native_value_scale_factor optional 0..1
Float
CF-style packing multiplier applied when decoding the source's stored integer...
Native Value Offset native_value_offset optional 0..1
Float
CF-style packing offset applied when decoding the source's stored integers to...
Unit Conversion Formula unit_conversion_formula conditionally core 0..1
String
The conversion from the source's native representation to the values in the c...
Target Concept Vocabulary target_concept_vocabulary recommended 0..1
String
The downstream health-data vocabulary that target_concept_id and `concept_s...
Target Concept Identifier target_concept_id recommended 0..1
String
Concept identifier for the variable in the vocabulary named by `target_concep...
Reason Concept ID Is Missing target_concept_id_missing_reason optional 0..1
MissingReasonEnum
Reason target_concept_id is null
Concept Status concept_status core 1
ConceptStatusEnum
Status of this variable's coverage in the target health-data vocabulary (`exi...
Concept Cross-References concept_mappings optional *
Uriorcurie
Cross-references binding this variable to other vocabularies and ontologies, ...
Value Data Type value_data_type core 1
DataTypeEnum
The data type of the stored exposure value
Plausible Minimum Value value_range_plausible_min recommended 0..1
Float
Physical / domain lower bound for plausible values (e
Plausible Maximum Value value_range_plausible_max recommended 0..1
Float
Physical / domain upper bound for plausible values (e
Conditional rules on this class
Rule Applied Preconditions Postconditions
slot_conditions {'standard_name': {'pattern': '^CF:'}} {'cf_cell_methods': {'required': True}}

Rule Applied Preconditions Postconditions
slot_conditions {'native_units_ucum': {'value_presence': 'PRESENT'}} {'unit_conversion_formula': {'required': True}}
Diagram & LinkML source
 classDiagram
    class VariableIdentity
    click VariableIdentity href "../../classes/VariableIdentity/"
      VariableIdentity : cf_cell_methods

      VariableIdentity : concept_mappings

      VariableIdentity : concept_status





        VariableIdentity --> "1" ConceptStatusEnum : concept_status
        click ConceptStatusEnum href "../../enums/ConceptStatusEnum/"



      VariableIdentity : native_units_ucum

      VariableIdentity : native_value_offset

      VariableIdentity : native_value_scale_factor

      VariableIdentity : standard_name

      VariableIdentity : target_concept_id

      VariableIdentity : target_concept_id_missing_reason





        VariableIdentity --> "0..1" MissingReasonEnum : target_concept_id_missing_reason
        click MissingReasonEnum href "../../enums/MissingReasonEnum/"



      VariableIdentity : target_concept_vocabulary

      VariableIdentity : unit_conversion_formula

      VariableIdentity : units_display

      VariableIdentity : units_ucum

      VariableIdentity : value_data_type





        VariableIdentity --> "1" DataTypeEnum : value_data_type
        click DataTypeEnum href "../../enums/DataTypeEnum/"



      VariableIdentity : value_range_plausible_max

      VariableIdentity : value_range_plausible_min

      VariableIdentity : variable_label

      VariableIdentity : variable_name

name: VariableIdentity
annotations:
  domain_of_use:
    tag: domain_of_use
    value: environmental_exposure
description: The identity and semantics of an environmental exposure variable — what
  physical quantity is being captured, in what units, and how it binds to community
  vocabularies. One per record.
title: Variable Identity
from_schema: https://w3id.org/linkml/microschemas/envar
see_also:
- https://cfconventions.org/standard-names.html
- https://ucum.org/
rank: 1000
slot_usage:
  variable_name:
    name: variable_name
    required: true
  standard_name:
    name: standard_name
    required: true
  units_ucum:
    name: units_ucum
    required: true
  concept_status:
    name: concept_status
    required: true
  value_data_type:
    name: value_data_type
    required: true
attributes:
  variable_name:
    name: variable_name
    annotations:
      tier:
        tag: tier
        value: core
      justification:
        tag: justification
        value: This is the handle under which the upstream product knows the variable
          (Daymet `tmax` vs gridMET `tmmx`). Without it the record cannot be traced
          back to the source product's variable, and a rerun cannot request the same
          quantity from the tool.
      explanation:
        tag: explanation
        value: Data tools give each measurement a short nickname, like `tmax` for
          maximum temperature. This is that nickname, written down exactly as the
          tool spells it, so you can go back to the source and find the same measurement
          again.
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: gaia_db/variable_source.variable_name; DeGAUSS/Amadeus emit
                  the short name only as a bare column header (tmax / tmmx)
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §F (Variable short name —
                  ✅ for GAIA)
              note:
                tag: note
                value: GAIA carries the variable short name first-class in variable_source.variable_name;
                  the combined stack surfaces it as a named slot.
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: cohort_addresses_geocoded_daymet CSV column header `tmax`
              note:
                tag: note
                value: 'DeGAUSS carries the short name only as the value column header,
                  not as a first-class named slot. Conservative: partial.'
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: gridmet_tmmx.csv column header `tmmx`; thredds_dataset.xml
                  long_name/standard_name = tmmx
              note:
                tag: note
                value: 'Amadeus carries the short name as a column header and in the
                  THREDDS long_name, not as a portable variable-name slot. Conservative:
                  partial.'
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: table_column_dictionary.column_name (literal column name)
              note:
                tag: note
                value: 'C-HER records each resource''s literal column_name, which
                  serves as the variable''s machine-readable handle; not a portable
                  sidecar short-name. Conservative: partial.'
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: out_of_layer
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: A tool-specific short name is an instance-layer handle; the
                  CODATA/I-ADOPT conceptual layer names the property canonically,
                  not the upstream tool's nickname.
    description: Short machine-readable name for the variable, usually the name the
      upstream tool uses for it (e.g. `tmax`, `tmmx`, `air.2m`). Identity only — not
      necessarily the column header in the companion data file; that binding lives
      in `DataLayout.value_column` (see envar_layout).
    title: Variable Name
    examples:
    - value: tmax
      description: Daymet daily maximum air temperature variable
    from_schema: https://w3id.org/linkml/microschemas/envar
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: string
    required: true
  variable_label:
    name: variable_label
    annotations:
      tier:
        tag: tier
        value: recommended
      justification:
        tag: justification
        value: Terse tool codes like `tmmx` are easy to misread (maximum vs mean)
          and force readers to consult external tool documentation. A plain-language
          label lets a human verify at a glance that the record describes the intended
          quantity.
      explanation:
        tag: explanation
        value: A friendly, spelled-out name for the measurement — like "daily maximum
          air temperature at 2 m" instead of the cryptic code `tmax` — so anyone reading
          the record knows what it is without decoding jargon.
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: gaia_db/variable_source.variable_description; JSON-LD variableMeasured.description
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §F (Variable description
                  / long name — ✅ for GAIA)
              note:
                tag: note
                value: GAIA carries a variable long name / description first-class
                  in variable_source.variable_description and the JSON-LD.
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: DeGAUSS CSVs carry no variable description / long name — only
                  the bare `tmax` column header.
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: thredds_dataset.xml description = "Daily Maximum Temperature
                  (2m)"; grid named daily_maximum_temperature
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §F (Variable description
                  / long name — ✅ for Amadeus)
              note:
                tag: note
                value: Amadeus's THREDDS metadata carries a human-readable variable
                  description first-class.
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: table_column_dictionary.name (human-readable, optional) / description
              note:
                tag: note
                value: 'C-HER''s optional `name` and required column `description`
                  carry a human-readable label, though `name` is optional. Conservative:
                  partial.'
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: out_of_layer
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: A display label is instance-layer presentation; CODATA's conceptual
                  layer names the property via I-ADOPT Object/Property, not a free-text
                  label.
    description: Human-readable label, e.g. "daily maximum air temperature at 2 m".
    title: Variable Label
    examples:
    - value: daily maximum air temperature at 2 m
    from_schema: https://w3id.org/linkml/microschemas/envar
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: string
  standard_name:
    name: standard_name
    annotations:
      tier:
        tag: tier
        value: core
      justification:
        tag: justification
        value: 'This is the cross-agency identifier that makes the variable interoperable:
          without it, `tmax` from one product and `tmmx` from another cannot be recognised
          by machines as the same physical quantity, so records cannot be pooled or
          harmonised across studies.'
      explanation:
        tag: explanation
        value: Different tools use different nicknames for the same thing, so scientific
          communities maintain shared official names for physical quantities (like
          "air_temperature"). Tagging the record with the official name lets computers
          tell that two datasets measure the same thing, no matter what each dataset
          called it.
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: gaia_db/variable_source.property_id and JSON-LD variableMeasured.propertyID
                  → vocab.nerc.ac.uk/standard_name/air_temperature (NERC/CF mirror)
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §F (CF standard name — ✅
                  for GAIA)
              note:
                tag: note
                value: GAIA is the only stack carrying a real CF standard name, via
                  the hand-authored NERC propertyID in variable_source / JSON-LD.
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: DeGAUSS carries no standard-name identifier — the quantity
                  is implicit in the `tmax` column name.
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: thredds_dataset.xml standard_name = "tmmx" (gridMET shortcode
                  overloaded, not a real CF term)
              note:
                tag: note
                value: 'Amadeus populates a standard_name slot but with the gridMET
                  shortcode rather than a CF term, so a CF lookup fails. Conservative:
                  partial.'
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: table_column_dictionary.column_tag_id (ontology tag planned
                  §8)
              note:
                tag: note
                value: 'C-HER''s column_tag / planned ontology encoding will tag columns
                  to its MORPH-built ontology, but no CF/standard-name binding exists
                  today. Conservative: partial.'
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: I-ADOPT Object + Property decomposition; DDI-CDI RepresentedVariable
                  (value domain + units)
              note:
                tag: note
                value: Naming the physical quantity canonically is exactly CODATA's
                  RepresentedVariable / I-ADOPT layer — its strongest zone — but it
                  names the concept, not this run's specific CURIE.
    description: The standard-name identifier for the physical quantity, as a CURIE
      so the schema privileges no single naming authority. Use a CF Convention Standard
      Name where one exists (`CF:air_temperature`, `CF:relative_humidity`); for health-relevant
      quantities CF does not define (e.g. Heat Index, WBGT), mint a term in the project
      registry (`ENVAR:heat_index`) or reuse an ontology term (`ECTO:...`). The prefix
      carries the authority; the slot name does not. Mandatory.
    title: Standard Name
    examples:
    - value: CF:air_temperature
      description: CF Standard Name for the Daymet daily Tmax scenario
    - value: CF:mass_concentration_of_pm2p5_ambient_aerosol_particles_in_air
      description: CF Standard Name for the ACAG PM2.5 scenario
    from_schema: https://w3id.org/linkml/microschemas/envar
    see_also:
    - https://cfconventions.org/standard-names.html
    - https://obofoundry.org/ontology/ecto.html
    slot_uri: dcterms:subject
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: uriorcurie
    required: true
  cf_cell_methods:
    name: cf_cell_methods
    annotations:
      tier:
        tag: tier
        value: conditionally_core
      justification:
        tag: justification
        value: 'A daily maximum and a daily mean of the same quantity carry the same
          standard name and units; only the aggregation statement tells them apart.
          Keeping the verbatim CF string also enables round-tripping against CF/NetCDF
          source products and the CF-consistency triple check over `standard_name`
          + `cf_cell_methods` + `units_ucum`. Conditionally-Core because the slot
          is CF-specific by design: it is mandatory when `standard_name` uses the
          `CF:` prefix (the context of SPEC.md validation rule 5), while a non-CF
          product genuinely has no verbatim `cell_methods` string to preserve  its
          vocabulary-neutral aggregation semantics live in the required `temporal_aggregation_method`.'
      explanation:
        tag: explanation
        value: 'A "daily temperature" value could be the day''s highest reading, its
          average, or its lowest  very different numbers. This short standard phrase
          (like "time: maximum") records which one it is, in the exact wording that
          climate-data software already understands.'
    description: 'CF `cell_methods` string describing how the value summarises sub-period
      values, e.g. `time: maximum` for Tmax, `time: mean` for daily mean.'
    title: CF Cell Methods
    comments:
    - 'Deliberately CF-specific  do not generalise. The vocabulary-neutral capture
      of aggregation semantics already exists as the required `TemporalReference.temporal_aggregation_method`
      enum (envar_temporal), which maps 1:1 to the temporal part of `cell_methods`;
      that enum is what machines should reason over. This slot instead preserves the
      *verbatim* CF expression. `cell_methods` is a structured mini-language (multi-axis
      forms like `area: mean time: maximum`, `within`/`over` qualifiers, `where` clauses)
      with no cross-vocabulary equivalent, so a "generalised" slot would be either
      a free string of unspecified syntax (losing machine-readability) or a newly
      minted EnVar aggregation grammar with no tooling support. Keeping the literal
      string also enables round-tripping against CF/NetCDF source products and the
      CF-consistency triple check over `standard_name` + `cf_cell_methods` + `units_ucum`
      (SPEC.md, validation rule 5). Contrast `standard_name`, which *was* generalised
      to a CURIE  that works because it is an identifier, and prefixes provide a
      standard generalisation mechanism; no such mechanism exists for expressions.'
    examples:
    - value: 'time: maximum'
      description: daily maximum (Tmax)
    - value: 'time: mean'
      description: mean over the aggregation period (e.g. annual-mean PM2.5)
    from_schema: https://w3id.org/linkml/microschemas/envar
    see_also:
    - https://cfconventions.org/cf-conventions/cf-conventions.html#cell-methods
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: string
  units_ucum:
    name: units_ucum
    annotations:
      tier:
        tag: tier
        value: core
      justification:
        tag: justification
        value: A number without units is uninterpretable — a value of 35 could be
          °C or °F, a factor-of-1.8 error in an exposure analysis. UCUM is the machine-readable
          form that health-data layers (e.g. OMOP's unit_concept_id) align to, so
          omitting it also blocks automated unit conversion and downstream integration.
      explanation:
        tag: explanation
        value: UCUM is a compact, machine-readable spelling of the unit — `Cel` for
          degrees Celsius, `ug/m3` for micrograms per cubic metre — so software can
          convert °C to °F or check units automatically without guessing what a human-written
          unit string means.
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: gaia_db/variable_source.unit_code (UCUM `CEL`) + unit_text;
                  JSON-LD variableMeasured.unitCode; external_exposure.unit_concept_id
                  8653
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §E (Native unit declared
                  — ✅ for GAIA)
              note:
                tag: note
                value: GAIA carries the unit as a first-class UCUM code (CEL) plus
                  the OMOP unit_concept_id.
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: thredds_dataset.xml units = "K"; gridmet_tmmx.cf_metadata.json
                  mirrors it
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §E (Native unit declared
                  — ✅ for Amadeus)
              note:
                tag: note
                value: Amadeus declares the native unit K in a machine-readable CF
                  metadata slot (though not in UCUM syntax).
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: DeGAUSS's `tmax` column has no unit annotation; °C is only
                  a container convention.
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: table_column_dictionary.column_unit_id (required for Value-tagged
                  columns)
              note:
                tag: note
                value: 'C-HER requires column_unit on Value-tagged columns, but the
                  unit vocabulary is not asserted to be UCUM. Conservative: partial.'
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: DDI-CDI RepresentedVariable (value domain + units); I-ADOPT
                  decomposition
              note:
                tag: note
                value: Units live at CODATA's RepresentedVariable layer — canonical
                  unit semantics — but not the specific UCUM string of this run's
                  file.
    description: The unit expressed in UCUM syntax, e.g. `Cel` for degrees Celsius,
      `K` for Kelvin, `ug/m3` for PM2.5 mass concentration.
    title: Units (UCUM)
    examples:
    - value: Cel
      description: degrees Celsius (Daymet Tmax)
    - value: ug/m3
      description: micrograms per cubic metre (PM2.5 mass concentration)
    from_schema: https://w3id.org/linkml/microschemas/envar
    see_also:
    - https://ucum.org/
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: string
    required: true
  units_display:
    name: units_display
    annotations:
      tier:
        tag: tier
        value: optional
      justification:
        tag: justification
        value: Keeps human-facing output (tables, plots, reports) readable without
          every consumer having to translate UCUM codes; omitting it risks each tool
          rendering the unit differently or mislabelling axes.
      explanation:
        tag: explanation
        value: The pretty version of the unit for people to read, like "°C". The machine
          version (`Cel`) is stored separately; this one exists purely for showing
          on screen or in print.
    description: Human-readable unit string for display purposes, e.g. `°C`.
    title: Display Units
    examples:
    - value: °C
    from_schema: https://w3id.org/linkml/microschemas/envar
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: string
  native_units_ucum:
    name: native_units_ucum
    annotations:
      tier:
        tag: tier
        value: recommended
      justification:
        tag: justification
        value: A value of 308 and a value of 35 can be the same temperature. When
          the source stores different units (or packed integers) than the companion
          file carries, the native unit is the anchor that lets a consumer check the
          conversion and re-read the source bytes; without it the sidecar's values
          cannot be traced back to the product.
      explanation:
        tag: explanation
        value: Data producers often store numbers in different units than the ones
          shown to users — Kelvin instead of Celsius, or compressed integers that
          need unpacking. This field records the unit the source actually uses, so
          anyone going back to the original files knows what the raw numbers mean.
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: GAIA stores °C as if it were always °C; only the OMOP-side
                  unit lands in value_as_number and the upstream native unit is not
                  on the row.
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: thredds_dataset.xml units = "K" (native) alongside the derived
                  value_celsius; gridmet_tmmx.csv value_kelvin column
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §D/§E (Value in native source
                  units — ✅ for Amadeus)
              note:
                tag: note
                value: Amadeus ships the native Kelvin value and its unit declaration
                  side by side with the converted Celsius.
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: DeGAUSS does the K→°C conversion inside the container, so the
                  native unit never appears in any output.
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: C-HER records one column_unit per column; it has no notion
                  of a distinct source-native unit and conversion.
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: out_of_layer
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: A source-native unit and its packing are instance-layer decode
                  details; CODATA's conceptual/represented layers do not carry per-run
                  storage conventions.
    description: UCUM unit of the values as the *source product stores them*, when
      that differs from `units_ucum` (the unit of the values in the companion data
      file). Omit when the source already stores values in `units_ucum` — absence
      means "no conversion happened". Declaring it makes `unit_conversion_formula`
      required.
    title: Native Units (UCUM)
    comments:
    - 'Added after the reverse gap survey (docs/reverse-gap-survey.md, 2026-07): all
      three worked pipelines surfaced the same gap independently  Amadeus ships `value_kelvin`/`value_celsius`
      twin columns, GAIA stores °C with no record of the K→°C math, and DeGAUSS converts
      inside the container so the native unit never appears in any output. The Amadeus
      translation had to park the native unit in a YAML comment because the schema
      had no slot for it; the GAIA scenario prototyped exactly this key as a hand-added
      `envar:*` PropertyValue in its JSON-LD catalog entry before it existed here.'
    examples:
    - value: K
      description: gridMET tmmx stores Kelvin; the Amadeus scenario emits Celsius
    from_schema: https://w3id.org/linkml/microschemas/envar
    see_also:
    - https://ucum.org/
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: string
  native_value_scale_factor:
    name: native_value_scale_factor
    annotations:
      tier:
        tag: tier
        value: optional
      justification:
        tag: justification
        value: Anyone re-reading the source grid directly (rather than the companion
          file) must unpack stored integers with exactly this factor; a wrong or missing
          factor yields physically plausible but wrong values, the worst kind of error.
      explanation:
        tag: explanation
        value: Big datasets often save space by storing small whole numbers that must
          be multiplied by a constant to get the real measurement. This is that constant.
    description: CF-style packing multiplier applied when decoding the source's stored
      integers to physical values (`physical = stored × scale_factor + add_offset`).
      Only meaningful alongside `native_units_ucum`.
    title: Native Value Scale Factor
    comments:
    - 'Added after the reverse gap survey (docs/reverse-gap-survey.md, 2026-07): the
      THREDDS metadata the Amadeus flow fetches declares `scale_factor = 0.1`, `add_offset
      = 220.0`, `_Unsigned`  the packed int16  Kelvin decode convention. The survey
      rated this the single most load-bearing no-home field it found: mis-decoding
      produces garbage temperatures, and nothing in the sidecar recorded it.'
    examples:
    - value: '0.1'
      description: gridMET tmmx packs Kelvin as unsigned int16 with scale 0.1
    from_schema: https://w3id.org/linkml/microschemas/envar
    see_also:
    - https://cfconventions.org/cf-conventions/cf-conventions.html#packed-data
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: float
  native_value_offset:
    name: native_value_offset
    annotations:
      tier:
        tag: tier
        value: optional
      justification:
        tag: justification
        value: The offset half of the unpacking convention; without it the scale factor
          alone still decodes to the wrong physical value.
      explanation:
        tag: explanation
        value: 'The second constant in the space-saving trick: after multiplying the
          stored number, add this to get the real measurement.'
    description: CF-style packing offset applied when decoding the source's stored
      integers to physical values (`physical = stored × scale_factor + add_offset`).
      Only meaningful alongside `native_units_ucum`.
    title: Native Value Offset
    comments:
    - Added after the reverse gap survey (docs/reverse-gap-survey.md, 2026-07) together
      with `native_value_scale_factor` — the other half of the packed-value decode
      convention the Amadeus THREDDS metadata declares and the sidecar previously
      lost.
    examples:
    - value: '220.0'
      description: gridMET tmmx packing offset (unpacks to true Kelvin)
    from_schema: https://w3id.org/linkml/microschemas/envar
    see_also:
    - https://cfconventions.org/cf-conventions/cf-conventions.html#packed-data
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: float
  unit_conversion_formula:
    name: unit_conversion_formula
    annotations:
      tier:
        tag: tier
        value: conditionally_core
      justification:
        tag: justification
        value: Twin value columns and silent container conversions are how factor-of-1.8
          unit errors enter exposure analyses undetected. Once native units are declared,
          the bridging math is the only record of how the file's values relate to
          the source's — it is what makes the conversion checkable rather than trusted.
      explanation:
        tag: explanation
        value: When the original data used different units, this spells out the exact
          arithmetic that turned them into the numbers in the data file — like showing
          your work in a calculation, so others can check it.
    description: The conversion from the source's native representation to the values
      in the companion data file, written out, e.g. `Cel = K - 273.15` or `K = stored
      × 0.1 + 220.0; Cel = K - 273.15`. Required whenever `native_units_ucum` is declared.
    title: Unit Conversion Formula
    comments:
    - 'Added after the reverse gap survey (docs/reverse-gap-survey.md, 2026-07): the
      Amadeus translation carried this exact math only as a YAML comment ("the schema
      has no slot for it"), and the GAIA scenario hand-added it as an `envar:unit_conversion`
      PropertyValue. The comparison table in the EnVar pipeline repo lists "K→°C conversion
      math recorded: ❌" for every pipeline  this slot is the fix.'
    examples:
    - value: K = stored * 0.1 + 220.0; Cel = K - 273.15
      description: gridMET tmmx unpack-then-convert chain in the Amadeus scenario
    from_schema: https://w3id.org/linkml/microschemas/envar
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: string
  target_concept_vocabulary:
    name: target_concept_vocabulary
    annotations:
      tier:
        tag: tier
        value: recommended
      justification:
        tag: justification
        value: '`target_concept_id` and `concept_status` are meaningless without knowing
          which vocabulary they refer to; naming it explicitly keeps the record portable
          across health-data layers (OMOP, BDC, ...) instead of silently assuming
          one.'
      explanation:
        tag: explanation
        value: Health databases each keep their own catalogue of codes for the things
          they record. This slot says which catalogue the record's health-data code
          (and its status) comes from — for example the OMOP catalogue used by many
          hospital research databases.
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: external_exposure.exposure_concept_id + exposure_type_concept_id
                  (32885) + unit_concept_id (8653) — OMOP vocabulary is the implicit
                  target
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §D (Exposure concept / variable
                  identity — ✅ for GAIA)
              note:
                tag: note
                value: The OMOP CDM is the target vocabulary itself; the concept slots
                  land the value against OHDSI concept ids.
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: DeGAUSS emits a bare `tmax` value with no target-vocabulary
                  binding.
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: Amadeus carries no target-vocabulary binding; the variable
                  is implicit in the `tmmx` column name.
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: C-HER's controlled vocabs (DCMI Type, IANA media types) describe
                  resource type/format, not a downstream health-data target vocabulary
                  for the variable.
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: out_of_layer
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: Binding to a downstream health-data layer is an instance/target
                  concern; CODATA aligns concepts across standards but names no single
                  target vocabulary.
    description: The downstream health-data vocabulary that `target_concept_id` and
      `concept_status` refer to, e.g. `omop` (OHDSI Standardised Vocabulary), `bdc`
      (BioData Catalyst). Names the vocabulary so the schema privileges no single
      health-data layer.
    title: Target Concept Vocabulary
    examples:
    - value: omop
      description: OHDSI Standardised Vocabulary (OMOP CDM)
    from_schema: https://w3id.org/linkml/microschemas/envar
    see_also:
    - https://athena.ohdsi.org/
    - https://biodatacatalyst.nhlbi.nih.gov/
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: string
  target_concept_id:
    name: target_concept_id
    annotations:
      tier:
        tag: tier
        value: recommended
      justification:
        tag: justification
        value: This is the hook that lets the environmental value land in a health
          database as a recognised concept. Recording it — or its documented absence
          — shows whether the vocabulary binding was attempted and against what, instead
          of leaving the linkage silent and unreproducible.
      explanation:
        tag: explanation
        value: Health databases store everything under numeric codes from a shared
          catalogue. This is that code for the environmental measurement, when one
          exists, so the exposure value can sit alongside clinical data under an identifier
          the database already knows.
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: external_exposure.exposure_concept_id (placeholder concept
                  present) + exposure_type_concept_id 32885
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §D (Exposure concept / variable
                  identity — ✅ for GAIA)
              note:
                tag: note
                value: GAIA fills the concept-id slot even though no real OMOP concept
                  is yet minted for daily-max-air-temperature; the binding exists.
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: No concept-id column in DeGAUSS output.
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: No concept-id column in Amadeus output.
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: C-HER binds no downstream concept id for the variable; only
                  planned ontology tags on columns (§8).
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: out_of_layer
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: A concrete concept id in a target vocabulary is instance-layer;
                  CODATA names the concept, not this run's downstream id.
    description: Concept identifier for the variable in the vocabulary named by `target_concept_vocabulary`
      (e.g. an OHDSI concept_id). Nullable with reason for environmental variables
      that lack coverage today.
    title: Target Concept Identifier
    examples:
    - value: '2005200123'
      description: illustrative OHDSI concept_id; in the canonical Tmax and PM2.5
        scenarios this slot is null with a missing reason
    from_schema: https://w3id.org/linkml/microschemas/envar
    see_also:
    - https://athena.ohdsi.org/
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: string
  target_concept_id_missing_reason:
    name: target_concept_id_missing_reason
    annotations:
      tier:
        tag: tier
        value: optional
      justification:
        tag: justification
        value: 'Without a stated reason, a null `target_concept_id` is ambiguous:
          downstream users cannot tell a genuine vocabulary gap from a pipeline that
          simply failed to look the concept up, and so cannot decide whether to fix
          the data or request a new concept.'
      explanation:
        tag: explanation
        value: When a code is missing, it matters why. This slot records the reason
          — for example that no such code has been invented yet — so an empty field
          is not mistaken for a processing mistake.
    description: Reason `target_concept_id` is null. Distinguishes "no concept yet
      exists in the target vocabulary" from "the pipeline did not resolve it".
    title: Reason Concept ID Is Missing
    examples:
    - value: not_provided_by_source
    from_schema: https://w3id.org/linkml/microschemas/envar
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: MissingReasonEnum
  concept_status:
    name: concept_status
    annotations:
      tier:
        tag: tier
        value: core
      justification:
        tag: justification
        value: A downstream system must know whether to expect a concept id. The explicit
          existing/proposed/gap status makes vocabulary gaps visible and countable
          rather than silently null — which is what drives vocabulary-extension requests
          for environmental variables.
      explanation:
        tag: explanation
        value: A simple status flag saying whether the health-data catalogue already
          has a code for this measurement, has one in the works, or has nothing yet.
          It turns a silent gap into an explicit, reportable fact.
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: GAIA fills a placeholder exposure_concept_id but carries no
                  existing/proposed/gap status flag saying whether a real OMOP concept
                  exists — an EnVar-novel slot.
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: DeGAUSS has no concept binding and so no coverage-status flag.
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: Amadeus has no concept binding and so no coverage-status flag.
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: C-HER carries no existing/proposed/gap coverage status for
                  a target vocabulary.
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: out_of_layer
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: A gap-status flag against a target vocabulary is instance/target
                  bookkeeping, outside CODATA's conceptual-alignment layer.
    description: Status of this variable's coverage in the target health-data vocabulary
      (`existing` / `proposed` / `gap`). Makes the vocabulary gap explicit rather
      than silent. Required.
    title: Concept Status
    examples:
    - value: gap
      description: no OMOP concept exists yet for daily Tmax
    from_schema: https://w3id.org/linkml/microschemas/envar
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: ConceptStatusEnum
    required: true
  concept_mappings:
    name: concept_mappings
    annotations:
      tier:
        tag: tier
        value: optional
      justification:
        tag: justification
        value: Cross-references to ontologies (ECTO, ENVO) and clinical codes (LOINC,
          SNOMED) let the variable be found and aligned across projects and communities;
          without them, cross-study harmonisation has to be redone by hand. Enrichment
          only — not needed to reproduce the value.
      explanation:
        tag: explanation
        value: Different scientific communities keep different dictionaries of concepts.
          This is a list of "also known as" links pointing to the matching entries
          in those dictionaries, so people searching any of them can still find this
          measurement.
    description: 'Cross-references binding this variable to other vocabularies and
      ontologies, each as a CURIE. One generic list rather than a slot per standard,
      so adding a vocabulary is a new prefix, not a schema change. Examples: `ECTO:0000012`
      (Environmental Conditions, Treatments and Exposures Ontology  cross-Monarch
      / cross-CHORDS alignment), `ENVO:01000339` (Environment Ontology  material
      or process exposed to), `LOINC:...` / `SNOMED:...` (where the variable has clinical
      coverage). Note: the *primary* downstream health-data binding, with its `existing`
      / `proposed` / `gap` status, stays in the structured `target_concept_*` slots
       this list is for additional, status-free cross-references.'
    title: Concept Cross-References
    examples:
    - value: ECTO:0000012
      description: exposure to temperature (ECTO) — one element of the cross-reference
        list for the Daymet daily Tmax scenario
    - value: ENVO:03000049
      description: temperature of air (ENVO) — a second element of the same cross-reference
        list
    from_schema: https://w3id.org/linkml/microschemas/envar
    see_also:
    - https://obofoundry.org/ontology/ecto.html
    - https://obofoundry.org/ontology/envo.html
    - https://loinc.org/
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: uriorcurie
    multivalued: true
  value_data_type:
    name: value_data_type
    annotations:
      tier:
        tag: tier
        value: core
      justification:
        tag: justification
        value: Tells consumers how to parse and analyse the values — continuous numbers,
          categories, and flags need different statistics and storage. Omitting it
          forces guessing from the data, which fails on ambiguous cases like 0/1 columns
          (count, flag, or category?).
      explanation:
        tag: explanation
        value: 'Says what kind of value to expect: a decimal number that can take
          any value (like a temperature), a yes/no flag, or a category. Software needs
          this to know how to read and summarise the data correctly.'
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: gaia_catalog meta_etl_*.json qudt:dataType (numeric/float4)
              evidence:
                tag: evidence
                value: examples/scenarios/standards/omop_gaia_daymet_tmax.yaml (value_data_type)
              note:
                tag: note
                value: GAIA registers the attribute's numeric qudt:dataType at dataset-registration
                  time; the EnVar translation carries it first-class as value_data_type.
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: DeGAUSS emits a numeric `tmax` column but declares no explicit
                  value data type; the type is implicit in the data.
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: Amadeus emits numeric value_kelvin/value_celsius columns with
                  no explicit value-data-type declaration.
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: table_column_dictionary.column_tag (Value) + column_unit (unit
                  present ⇒ numeric)
              note:
                tag: note
                value: 'C-HER''s Value tag plus the presence/absence of a column_unit
                  distinguishes numeric from free-text value columns, but not the
                  full continuous/categorical/flag taxonomy. Conservative: partial.'
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: DDI-CDI RepresentedVariable value domain (numeric vs categorical
                  value domain)
              note:
                tag: note
                value: A value domain is exactly what CDI's RepresentedVariable carries,
                  so the numeric/categorical distinction lives at CODATA's represented
                  layer.
    description: The data type of the stored exposure value.
    title: Value Data Type
    examples:
    - value: continuous_numeric
    from_schema: https://w3id.org/linkml/microschemas/envar
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: DataTypeEnum
    required: true
  value_range_plausible_min:
    name: value_range_plausible_min
    annotations:
      tier:
        tag: tier
        value: recommended
      justification:
        tag: justification
        value: 'Gives automated quality checks a sanity band: without it, unit mix-ups
          and corrupted values (e.g. a Tmax of 350 from unconverted Kelvin) pass silently
          into downstream analyses.'
      explanation:
        tag: explanation
        value: The lowest value that would still make physical sense — for example
          -50 °C for outdoor air temperature. Anything below it is probably an error;
          this is a warning signal, not a hard rule.
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: gaia_db/variable_source.min_value (−50); also JSON-LD variableMeasured
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §F (Variable valid range
                  min/max — ✅ for GAIA)
              note:
                tag: note
                value: GAIA carries a first-class min_value (−50) as variable metadata.
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: DeGAUSS carries no plausible-range metadata.
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: Amadeus carries no plausible-range bounds; only a _FillValue
                  sentinel.
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: C-HER column metadata carries no per-variable plausible min/max.
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: I-ADOPT Constraint on the Property; DDI-CDI value-domain bounds
              note:
                tag: note
                value: Plausible domain bounds are naturally an I-ADOPT Constraint
                  on the property / a CDI value-domain restriction at the conceptual
                  layer.
    description: Physical / domain lower bound for plausible values (e.g. -50 °C for
      ambient Tmax). Not a hard validation bound; sanity-check signal.
    title: Plausible Minimum Value
    examples:
    - value: '-50'
      description: plausible lower bound for ambient Tmax in °C
    from_schema: https://w3id.org/linkml/microschemas/envar
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: float
  value_range_plausible_max:
    name: value_range_plausible_max
    annotations:
      tier:
        tag: tier
        value: recommended
      justification:
        tag: justification
        value: 'Together with the plausible minimum, this gives automated quality
          checks a sanity band: without it, unit mix-ups and corrupted values slip
          silently past validation into exposure analyses.'
      explanation:
        tag: explanation
        value: The highest value that would still make physical sense — for example
          60 °C for outdoor air temperature. Anything above it likely signals a unit
          mix-up or a data error worth investigating.
      covered_by:
        tag: covered_by
        annotations:
          omop_gaia:
            tag: omop_gaia
            annotations:
              extent:
                tag: extent
                value: full
              status:
                tag: status
                value: verified
              where:
                tag: where
                value: gaia_db/variable_source.max_value (60); also JSON-LD variableMeasured
              evidence:
                tag: evidence
                value: EnVar/examples/heat/COMPARISON.md §F (Variable valid range
                  min/max — ✅ for GAIA)
              note:
                tag: note
                value: GAIA carries a first-class max_value (60) as variable metadata.
          degauss:
            tag: degauss
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: DeGAUSS carries no plausible-range metadata.
          amadeus:
            tag: amadeus
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: Amadeus carries no plausible-range bounds; only a _FillValue
                  sentinel.
          cher:
            tag: cher
            annotations:
              extent:
                tag: extent
                value: absent
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: no column
              note:
                tag: note
                value: C-HER column metadata carries no per-variable plausible min/max.
          codata:
            tag: codata
            annotations:
              extent:
                tag: extent
                value: partial
              status:
                tag: status
                value: asserted
              where:
                tag: where
                value: I-ADOPT Constraint on the Property; DDI-CDI value-domain bounds
              note:
                tag: note
                value: Plausible domain bounds are naturally an I-ADOPT Constraint
                  on the property / a CDI value-domain restriction at the conceptual
                  layer.
    description: Physical / domain upper bound for plausible values (e.g. 60 °C for
      ambient Tmax).
    title: Plausible Maximum Value
    examples:
    - value: '60'
      description: plausible upper bound for ambient Tmax in °C
    from_schema: https://w3id.org/linkml/microschemas/envar
    owner: VariableIdentity
    domain_of:
    - VariableIdentity
    range: float
rules:
- preconditions:
    slot_conditions:
      standard_name:
        name: standard_name
        pattern: '^CF:'
  postconditions:
    slot_conditions:
      cf_cell_methods:
        name: cf_cell_methods
        required: true
  description: CF-based products (a `CF:`-prefixed `standard_name`) must preserve
    the verbatim `cell_methods` string — the context of SPEC.md validation rule 5
    and of the `conditionally_core` tier on `cf_cell_methods`. Non-CF products are
    exempt; their aggregation semantics live in the required `temporal_aggregation_method`.
- preconditions:
    slot_conditions:
      native_units_ucum:
        name: native_units_ucum
        value_presence: PRESENT
  postconditions:
    slot_conditions:
      unit_conversion_formula:
        name: unit_conversion_formula
        required: true
  description: 'Declaring native units is declaring a conversion: once `native_units_ucum`
    says the source stored something other than `units_ucum`, the math that bridged
    them must be written down or the sidecar''s values cannot be traced back to the
    source bytes (tier conditionally_core context "native units declared").'

See Also

Identifier and Mapping Information

Annotations

property value
domain_of_use environmental_exposure

Schema Source

Mappings

Mapping Type Mapped Value
self envar:VariableIdentity
native envar:VariableIdentity