Versions Compared

Key

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

...

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
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 wildfires062096
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

grib_file = 'cams_AQ_forecast.grib', codes_write)

# Dictionary matching ADS API key/value pairs to grib key/value pairs
definitions = {
    'variable': {
        'ammonia': {
            'parameterNumber': 0,
            'constituentType': 9},
        'carbon_monoxide': {
            'parameterNumber': 0,
            'constituentType': 4},
        'dust': {
            'parameterNumber': 0,      # Mass density kg/m3
            'constituentType': 62001}, # Dust dry
        'non_methane_vocs': {
            'parameterNumber': 0,
            'constituentType': 60013},
        'nitrogen_monoxide': {
            'parameterNumber': 0,
            'constituentType': 11},
        'nitrogen_dioxide': {
            'parameterNumber': 0,
            'constituentType': 5},
        'ozone': {
            'parameterNumber': 0,   # Mass density kg/m3
            'constituentType': 0},
        'peroxyacyl_nitrates': {
            'parameterNumber': 0,
            'constituentType': 60018},
        'particulate_matter_10um': {
            'parameterNumber': 0,
            'constituentType': 40008},
        'particulate_matter_2.5um': {
            'parameterNumber': 0,
            'constituentType': 40009},
        'pm2.5_anthropogenic_wood_burning_carbon': {
            'parameterNumber': 0,
            'constituentType': 62098},
        'pm2.5_anthropogenic_fossil_fuel_carbon': {
            'parameterNumber': 0,
            'constituentType': 62097},
        'pm10_wildfires': {
            'parameterNumber': 0,
            'constituentType': 62096},
        'residential_elementary_carbon': {
            'parameterNumber': 0,
            'constituentType': 62094},
        'secondary_inorganic_aerosol': {
            'parameterNumber': 0,
            'constituentType': 62099},
        'sulphur_dioxide': {
            'parameterNumber': 0,
            'constituentType': 8},
        'total_elementary_carbon': {
            'parameterNumber': 0,
            'constituentType': 62095},

        'alder_pollen': {
            'parameterNumber': 59,     # Number Concentration (1/m3)
            'constituentType': 62100},
        'birch_pollen': {
            'parameterNumber': 59,
            'constituentType': 62101},
        'grass_pollen': {
            'parameterNumber': 59,
            'constituentType': 62300},
        'mugwort_pollen': {
            'parameterNumber': 59,
            'constituentType': 62201},
        'olive_pollen': {
            'parameterNumber': 59,
            'constituentType': 64002},
        'ragweed_pollen': {
            'parameterNumber': 59,
            'constituentType': 62200}
    },
    'model': {
        'chimere': {
            'centre': 85,      # France
            'subCentre': 200},
        'dehm': {
            'centre': 85,
            'subCentre': 203},
        'emep': {
            'centre': 88,      # Oslo
            'subCentre': 0},
        'ensemble': {
            'centre': 85,      # France
            'subCentre': 2},
        'euradim': {
            'centre': 85,      # France
            'subCentre': 201},
        'gemaq': {
            'centre': 85,
            'subCentre': 204},
        'lotos': {
            'centre': 99,
            'subCentre': 0},
        'match': {
            'centre': 82,      # Norrkoping
            'subCentre': 98},
        'mocage': {
            'centre': 85,      # Meteo France
            'subCentre': 1},
        'silam': {
            'centre': 86,      # Helsinki
            'subCentre': 0},
      }
}


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

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

 'centre': 85,
             # Does this message match the key/value pairs in grib_defn?
            match = True
        'subCentre': 206}
    }
}


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

    field = {}
    for gribapi_key, value_to_grib_value in grib_defndefinitions.items():
        for api_value, grib_defn in     msg_value = codes_get(msg, grib_key,value_to_grib.items():

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

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

    return field


# Loop over messages in a grib file, identifying all fieldsbreak
count = 0
with open(grib_file) as f:
    while True:
  if match:
     msg = codes_grib_new_from_file(f)
        if msg is None: field[api_key] = api_value

        if api_key not in breakfield:
        count += 1

  raise Exception('Unrecognised field')

    return field


def  trymain(grib_file, output_filename_template=None):
    """Read all fields in the GRIB file, identify the model fieldand = identify_field(msg)variable of
        finally:
            codes_release(msg)

each, and optionally write them to output files, split by model or
       variable or both.

  print('Field ' + str(count) + 'Any is:instance 'of + repr(field))
"<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')