|
| 1 | +#! /bin/env python3 |
1 | 2 |
|
| 3 | +"""Utilities for parsing and organizing diagnostic fieldnames for chemical |
| 4 | +species in a given chemistry scheme. |
| 5 | +""" |
| 6 | +import glob |
| 7 | +import re |
| 8 | +import os |
2 | 9 |
|
3 | | -## chemistry species diags to not add to master list |
4 | | -__CHEM_SPECIES = ['BC_A', 'BC_AC', 'BC_AI', 'BC_AX', 'BC_N', 'BC_NI', |
5 | | - 'CFC11', 'CFC12', 'CH4', 'CO2', 'DMS', 'DST_A2', 'DST_A3', |
6 | | - 'H2O', 'H2O2', 'H2SO4', 'N2O', 'OM_AC', 'OM_AI', 'OM_NI', |
7 | | - 'SO2', 'SO4_A1', 'SO4_A2', 'SO4_AC', 'SO4_NA', 'SO4_PR', |
8 | | - 'SOA_A1', 'SOA_LV', 'SOA_NA', 'SOA_SV', |
9 | | - 'SS_A1', 'SS_A2', 'SS_A3', 'isoprene', 'monoterp'] |
| 10 | +## Save our location |
| 11 | +__MYDIR = os.path.abspath(os.path.dirname(__file__)) |
| 12 | +__CAMDIR = os.path.dirname(os.path.dirname(__MYDIR)) |
| 13 | +__CHEMDIR = os.path.join(__CAMDIR, "src", "chemistry") |
10 | 14 |
|
11 | 15 | ## chemistry diag pre- and post-fixes |
12 | 16 | ## Each list entry is a pair of possible new chemistry names |
13 | | -__CHEM_DIAG_PRE_POST = [('GS_', ''), ('AQ_', ''), ('AQ_', '_OCW')] |
| 17 | +__CHEM_DIAG_PRE_POST = [('GS_', ''), ('AQ_', ''), ('AQ_', '_OCW'), |
| 18 | + ('sink_', ''), ('sink_', '_S'), |
| 19 | + ('CT_', ''), ('SF', ''), ('emis_', ''), |
| 20 | + ('D', 'CHM'), ('F', '_fvm'), ('TA', ''), ('TM', ''), |
| 21 | + ('VD', ''), ('', 'CONU'), ('', 'DDF'), ('', 'DDV'), |
| 22 | + ('', 'DTQ'), ('', 'GVF'), ('', 'INS'), ('', 'SBC'), |
| 23 | + ('', 'SBS'), ('', 'SF'), ('', 'SFSBC'), ('', 'SFSBD'), |
| 24 | + ('', 'SFSBS'), ('', 'SFSEC'), ('', 'SFSED'), |
| 25 | + ('', 'SFSES'), ('', 'SFSIC'), ('', 'SFSID'), |
| 26 | + ('', 'SFSIS'), ('', 'SFWET'), ('', 'SFWETC'), |
| 27 | + ('', 'SIC'), ('', 'SIS'), ('', 'TBF'), ('', 'WET'), |
| 28 | + ('', 'WETC'), ('', '_CHML'), ('', '_CHMP'), |
| 29 | + ('', '_SRF'), ('', '_fvm'), ('', '_mixnuc1'), |
| 30 | + ('', '_num'), ('', '_qneg3'), ('', '_qneg3_col'), |
| 31 | + ('', '_sfcoag1'), ('', '_sfcsiz3'), ('', '_sfcsiz4'), |
| 32 | + ('', '_sfgaex2')] |
| 33 | + |
| 34 | +## Find chem species in mo_sim_dat.F90 |
| 35 | +__SOLSYM_RE = re.compile(r"solsym[(][: 0-9]+[)] = [(]/(.*)$") |
| 36 | +__END_SSYM_RE = re.compile(r"(.*)/[)]") |
| 37 | + |
| 38 | +def read_fieldname_file(filename): |
| 39 | + """Read a fieldname file and return all fieldnames as a list.""" |
| 40 | + diag_fieldname_file = os.path.join(__MYDIR, filename) |
| 41 | + all_fieldnames = [] |
| 42 | + with open(diag_fieldname_file, mode='r') as infile: |
| 43 | + for line in infile: |
| 44 | + fieldnames = [x.strip() for x in line.split()] |
| 45 | + all_fieldnames.extend(fieldnames) |
| 46 | + # end for |
| 47 | + # end with |
| 48 | + return all_fieldnames |
| 49 | + |
| 50 | +def parse_chem_spec_line(species_text): |
| 51 | + """Extract and return a list of chemical species names from the |
| 52 | + Fortran line fragment, <species_text>. |
| 53 | + """ |
| 54 | + # Store species without quotes |
| 55 | + match_text = species_text.rstrip('[/), &]') |
| 56 | + slist = [x.strip("[' ]") for x in match_text.split(',')] |
| 57 | + return slist |
| 58 | + |
| 59 | +def read_chem_species(chem_name): |
| 60 | + """Extract species names from the mo_sim_dat.F90 file from the |
| 61 | + chemistry scheme represented by <chem_name>. Return a list of |
| 62 | + species names extracted from solsym entries. |
| 63 | + """ |
| 64 | + # Validate directory exists |
| 65 | + chem_src_dir = os.path.join(__CHEMDIR, f"pp_{chem_name}") |
| 66 | + if not os.path.isdir(chem_src_dir): |
| 67 | + emsg = f"ERROR: read_chem_species cannot find {chem_src_dir}" |
| 68 | + raise FileNotFoundError(emsg) |
| 69 | + # end if |
| 70 | + |
| 71 | + species_list = [] |
| 72 | + filepath = os.path.join(chem_src_dir, "mo_sim_dat.F90") |
| 73 | + |
| 74 | + try: |
| 75 | + in_solsym = False |
| 76 | + with open(filepath, 'r') as infile: |
| 77 | + for line in infile: |
| 78 | + beg_match = __SOLSYM_RE.match(line.strip()) |
| 79 | + end_match = __END_SSYM_RE.match(line.strip()) |
| 80 | + if beg_match is not None: |
| 81 | + slist = parse_chem_spec_line(beg_match.group(1)) |
| 82 | + species_list.extend(slist) |
| 83 | + in_solsym = end_match is None |
| 84 | + if not in_solsym: |
| 85 | + # We are done with this file, one-line solsym def |
| 86 | + exit |
| 87 | + # end if |
| 88 | + elif in_solsym: |
| 89 | + if end_match is not None: |
| 90 | + in_solsym = False |
| 91 | + slist = parse_chem_spec_line(end_match.group(1)) |
| 92 | + else: |
| 93 | + slist = parse_chem_spec_line(line.strip()) |
| 94 | + # end if |
| 95 | + species_list.extend(slist) |
| 96 | + if not in_solsym: |
| 97 | + # We are done with this file |
| 98 | + exit |
| 99 | + # end if |
| 100 | + # end if |
| 101 | + # end for |
| 102 | + # end with |
| 103 | + except FileNotFoundError: |
| 104 | + emsg = f"File mo_sim_dat.F90 not found in {chem_src_dir}" |
| 105 | + raise FileNotFoundError(emsg) |
| 106 | + # end try |
| 107 | + |
| 108 | + return species_list |
| 109 | + |
| 110 | +def all_chem_names(chem_name=None): |
| 111 | + """Return a set containing all chemistry diagnostic names for one |
| 112 | + chemistry scheme (chem_name==None) or for all chemistry schemes |
| 113 | + (chem_name!=None). |
| 114 | + """ |
| 115 | + diag_names = set() |
| 116 | + if chem_name != None: |
| 117 | + all_species = read_chem_species(chem_name) |
| 118 | + else: |
| 119 | + all_chem_file = os.path.join(__MYDIR, "chemistry_fieldlist.txt") |
| 120 | + all_species = read_fieldname_file(all_chem_file) |
| 121 | + # end if |
| 122 | + for chem_speci in all_species: |
| 123 | + diag_names.add(chem_speci) |
| 124 | + for decor in __CHEM_DIAG_PRE_POST: |
| 125 | + diag_names.add(f"{decor[0]}{chem_speci}{decor[1]}") |
| 126 | + # end if |
| 127 | + # end for |
| 128 | + return diag_names |
| 129 | + |
| 130 | +############################################################################### |
| 131 | + |
| 132 | +if __name__ == "__main__": |
| 133 | + all_specs = set() |
| 134 | + chem_dirs = glob.glob(os.path.join(__CHEMDIR, "pp_*")) |
| 135 | + for chem_name in [os.path.basename(x)[3:] for x in chem_dirs]: |
| 136 | + if chem_name != "none": |
| 137 | + all_specs |= set(read_chem_species(chem_name)) |
| 138 | + # end if |
| 139 | + # end for |
| 140 | + print(f"{sorted(all_specs)}") |
0 commit comments