Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The tables below show the mapping. Below that is some example Python code showing how this information can be used with ecCodes to identify the model and variable of each field in a GRIB file.

ModelcentresubCentre
CHIMERE85200
DEHM85203
EMEP880
Ensemble median852
EURAD-IM85201
GEM-AQ85204
LOTOS-EUROS990
MATCH8298
MOCAGE851
SILAM860
MINNI85205
MONARCH85206


VariableparameterNumberconstituentType
Alder pollen5962100
Ammonia09
Birch pollen5962101
Carbon monoxide04
Dust062001
Formaldehyde07
Glyoxal010038
Grass pollen5962300
Mugwort pollen5962201
Nitrogen dioxide05
Nitrogen monoxide011
Non-methane VOCs060013
Olive pollen5964002
Ozone00
Particulate matter < 10um (PM10)040008
Particulate matter < 2.5um (PM2.5)040009
Peroxyacyl nitrates (PANs)060018
PM10 from wildfiresRagweed pollen5962200
PM2.5, total organic matter only0
62096
62010
PM10, sea salt (dry) only062008
PM10, wildfires only062096
Ragweed pollen5962200
Residential elementary carbon062094
Secondary inorganic aerosol (SIA)062099
Sulphur dioxide08
Total elementary carbon062095


Code Block
from eccodes import (
    codes_grib_new_from_file, codes_get, codes_release, codes_write)

grib_file = 'cams_AQ_forecast.grib'

# Dictionary matching # Dictionary matching ADS API key/value pairs to grib key/value pairs
definitions = {
    'variable': {
        'ozoneammonia': {
            'parameterNumber': 0,   # Mass density (kg/m3)
                 'constituentType': 09},
        'carbon_monoxide': {
            'parameterNumber': 0,
            'constituentType': 4},
        'ammoniadust': {
            'parameterNumber': 0,
            'constituentType': 962001},
        'non_methane_vocsformaldehyde': {
            'parameterNumber': 0,
            'constituentType': 600137},
        'nitrogen_monoxideglyoxal': {
            'parameterNumber': 0,
            'constituentType': 1110038}, 
        'nitrogennon_methane_dioxidevocs': {
            'parameterNumber': 0,
            'constituentType': 560013},
        'peroxyacylnitrogen_nitratesmonoxide': {
            'parameterNumber': 0,
            'constituentType': 6001811},
        'particulatenitrogen_matter_10umdioxide': {
            'parameterNumber': 0,
            'constituentType': 400085},
        'particulate_matter_2.5umozone': {
            'parameterNumber': 0,
            'constituentType': 400090},
        'pm10peroxyacyl_wildfiresnitrates': {
            'parameterNumber': 0,
            'constituentType': 6209660018},
        'sulphurparticulate_matter_dioxide10um': {
            'parameterNumber': 0,
            'constituentType': 840008},
        'birch_pollenparticulate_matter_2.5um': {
            'parameterNumber': 590,
     # Number Concentration (1/m3)
            ''constituentType': 6210140009},
        'grass_pollenpm2.5_anthropogenic_wood_burning_carbon': {
            'parameterNumber': 590,
            'constituentType': 6230062098},
        'olive_pollenpm2.5_anthropogenic_fossil_fuel_carbon': {
            'parameterNumber': 590,
            'constituentType': 6400262097},
	        'ragweed_pollen'pm2.5_total_organic_matter': {
                   'parameterNumber': 590,
            'constituentType': 6220062010},
           'dustpm10_sea_salt_dry': {
            'parameterNumber': 0,      # Mass density kg/m3
            'constituentType': 6200162008},
        'pm10_wildfires': {
    'secondary_inorganic_aerosol': {
            'parameterNumber': 0,
            'constituentType': 6209962096},
    },
    'modelresidential_elementary_carbon': {
            'chimereparameterNumber': {0,
            'centreconstituentType': 8562094},
      # France  'secondary_inorganic_aerosol': {
            'subCentreparameterNumber': 200}0,
            'emepconstituentType': {62099},
        'sulphur_dioxide': {
     'centre': 88,      # Oslo'parameterNumber': 0,
            'subCentreconstituentType': 08},
        'ensembletotal_elementary_carbon': {
            'centreparameterNumber': 85,      # France0,
            'subCentreconstituentType': 262095},
        'euradimalder_pollen': {
            'centreparameterNumber': 8559,     # # FranceNumber Concentration (1/m3)
            'subCentreconstituentType': 20162100},
        'matchbirch_pollen': {
            'centreparameterNumber': 82,      # Norrkoping59,
            'subCentreconstituentType': 9862101},
        'mocagegrass_pollen': {
            'centreparameterNumber': 8559,
      #  Meteo France
            'subCentreconstituentType': 162300},
        'silammugwort_pollen': {
            'centreparameterNumber': 86,      # Helsinki59,
            'subCentreconstituentType': 062201},
        'lotosolive_pollen': {
            'centreparameterNumber': 9959,
            'subCentreconstituentType': 064002},
        'gemaqragweed_pollen': {
            'centreparameterNumber': 8559,
            'subCentreconstituentType': 204},62200}
    },
    'model': {
        'dehmchimere': {
            'centre': 85,      # France
            'subCentre': 203200},
       }
}


def identify_field(msg): 'dehm': {
    """Return a dict identifying   the input grib message"""

'centre': 85,
           field = {}'subCentre': 203},
    for api_key, value_to_grib in definitions.items(): 'emep': {
        for api_value, grib_defn in value_to_grib.items():

  'centre': 88,      # Oslo
    # Does this message match the key/value pairs in grib_defn?'subCentre': 0},
            match = True'ensemble': {
            for grib_key'centre': 85, grib_value in grib_defn.items():
   # France
            msg_value = codes_get(msg, grib_key,'subCentre': 2},
        'euradim': {
            'centre': 85,      # France
         ktype=type(grib_value))
   'subCentre': 201},
        'gemaq': {
   if msg_value != grib_value:
      'centre': 85,
             match = False'subCentre': 204},
        'lotos': {
             break'centre': 99,
            if match:'subCentre': 0},
        'match': {
       field[api_key] = api_value

   'centre': 82,    if api_key not in field:# Norrkoping
            raise Exception('Unrecognised field')

'subCentre': 98},
     return field


# Loop over messages in a grib file, identifying all fields
count = 0
with open(grib_file) as f:
'mocage': {
            'centre': 85,    while True:  # Meteo France
        msg = codes_grib_new_from_file(f)
  'subCentre': 1},
     if msg is None'silam': {
            break
 'centre': 86,       count += 1

# Helsinki
        try:
    'subCentre': 0},
       field = identify_field(msg)
'minni': {
         finally:
   'centre': 85,
             codes_release(msg)
'subCentre': 205},
        print('Field ' + str(count) + ' is: ' + repr(field))

'monarch': {
            'centre': 85,
            'subCentre': 206}
    }
}


def identify_field(msg):
    """Return a dict identifying the input grib message"""

    field = {}
    for api_key, value_to_grib in definitions.items():
        for api_value, grib_defn in value_to_grib.items():

            # Does this message match the key/value pairs in grib_defn?
            match = True
            for grib_key, grib_value in grib_defn.items():
                msg_value = codes_get(msg, grib_key,
                                      ktype=type(grib_value))
                if msg_value != grib_value:
                    match = False
                    break
            if match:
                field[api_key] = api_value

        if api_key not in field:
            raise Exception('Unrecognised field')

    return field


def main(grib_file, output_filename_template=None):
    """Read all fields in the GRIB file, identify the model and variable of
       each, and optionally write them to output files, split by model or
       variable or both.

       Any instance of "<model>" or "<variable>" in output_filename_template
       will be replaced by the associated model or variable string for the
       field, e.g. output_filename_template='<model>.<variable>.grib'
    """

    fields_written = {}

    # Loop over messages in a grib file, identifying all fields
    count = 0
    with open(grib_file) as fin:
        while True:
            msg = codes_grib_new_from_file(fin)
            if msg is None:
                break
            count += 1

            try:
                field = identify_field(msg)
                print('Field ' + str(count) + ' is: ' + repr(field))

                # Write the field to an output file?
                if output_filename_template:
                    name = output_filename_template
                    for k, v in field.items():
                        name = name.replace(f'<{k}>', v)
                    if name not in fields_written:
                        fields_written[name] = 0
                        mode = 'w'
                    else:
                        mode = 'a'
                    with open(name, mode + 'b') as fout:
                        codes_write(msg, fout)
                    fields_written[name] += 1

            finally:
                codes_release(msg)

    for name, n in fields_written.items():
        print(f'Wrote {n} fields to {name}')


if __name__ == '__main__':
    main('mydata.grib',
         output_filename_template='<model>.<variable>.grib')