Source code for pycif.plugins.models.TM5.io.inputs.make_fluxes

import filecmp
import os
import shutil

import numpy as np
import pandas as pd
import xarray as xr
from netCDF4 import Dataset

from ......utils import path

# JvP 20210521: added import statements, MODULE_NAME module level logger
import logging
import sys
from ......utils.check.errclass import CifRuntimeError
MODULE_NAME = __name__[__name__.index('TM5'):] if 'TM5' in __name__ else __name__
logger = logging.getLogger(MODULE_NAME)


# Original make_fluxes function by A. Berchet
[docs] def make_fluxes_AB(self, data, runsubdir, datei, mode): """Make emission file for TM5 Args: self (pycif.utils.classes.fluxes.Flux): Flux plugin with all attributes data (Plugin): information on flux species runsubdir (str): directory to the current run nho (int): number of hours in the run mode (str): running mode: 'fwd', 'tl' or 'adj' """ # Here I print the data that is available for CH4 at that step # Loop over chemistry.acspecies for more general cases print("AAAAAAAAAAAAAAAA") print(data.datastore[("flux", "CH4")]) # Now I link the prior fluxes to a fixed name, to be put in # PyShell.em.apri.filename in params.py flx_datastore = data.datastore[("flux", "CH4")] ref_aprior = f"{flx_datastore['dirorig']}/{flx_datastore['fileorig']}" target_prior = f"{runsubdir}/prior_emissions.nc" path.link(ref_aprior, target_prior) # Now you need to dump the updated fluxes for the present iteration # PyShell.em.filename to be set to iter_emissions.nc if "spec" in flx_datastore and mode in ["fwd", "tl"]: iter_flx = f"{runsubdir}/iter_emissions.nc" self.flux.write("CH4", iter_flx, flx_datastore["spec"]) # Do the same for the increments if TL computation if "incr" in flx_datastore and mode in ["tl"]: incr_flx = f"{runsubdir}/incr_emissions.nc" self.flux.write("CH4", incr_flx, flx_datastore["incr"])
# # # datastore = { # trid: data.datastore[trid] # for trid in data.datastore # if trid[0] in ["flux", "bioflux"] # } # # # List of dates for which emissions are needed # list_dates = self.input_dates[datei] # # # Getting the right emissions # # Loop on all species # # If in datastore, take data, otherwise, link to original EMISSIONS # list_trid = [("flux", spec) # for spec in self.chemistry.emis_species.attributes] # # for trid in list_trid: # spec = trid[1] # emis_type = trid[0] # flx_plg = self.flux # if trid in datastore: # pass # # # If spec not explicitly defined in datastore, # # fetch general component information if available # elif trid not in datastore and (emis_type, "") in datastore: # trid = (emis_type, "") # else: # continue # # # File # file_emisout = "{}/emission.nc".format(runsubdir) # file_emisincrout = "{}/emission.increment.nc".format( # runsubdir) # # tracer = datastore[trid] # dirorig = tracer["dirorig"] # fileorig = tracer["fileorig"] # fileemis = datei.strftime("{}/{}".format(dirorig, fileorig)) # # # If no data is provided, just copy from original file # if "spec" not in tracer: # linked = False # # # If does not exist, just link # if not os.path.isfile(file_emisout): # path.link(fileemis, file_emisout) # linked = True # # # Otherwise, check for difference # if not linked: # if not filecmp.cmp(fileemis, file_emisout): # with Dataset(fileemis, "r") as fin: # emisin = fin.variables[spec][:] # emisin = xr.DataArray( # emisin, # coords={"time": list_dates}, # dims=("time", "lev", "lat", "lon"), # ) # flx_plg.write(spec, file_emisout, emisin) # # # Repeat operations for tangent linear # if mode != "tl": # continue # # if "spec" not in tracer: # # If does not exist, just link # if not os.path.isfile(file_emisincrout): # shutil.copy(fileemis, file_emisincrout) # # flx_incr = xr.DataArray( # np.zeros( # ( # len(list_dates), # self.nlevemis if emis_type == "flux" # else self.nlevemis_bio, # self.domain.nlat, # self.domain.nlon, # ) # ), # coords={"time": list_dates}, # dims=("time", "lev", "lat", "lon"), # ) # # # The function write should be available in fluxes.tm5 # flx_plg.write(spec, file_emisincrout, flx_incr) # # else: # # Replace existing link by copy of original file to modify it # path.copyfromlink(file_emisout) # # # Put in dataset and write to input # flx_fwd = datastore[trid]["spec"] # flx_plg.write(spec, file_emisout, flx_fwd) # # if mode == "tl": # path.copyfromlink(file_emisincrout) # flx_tl = datastore[trid].get("incr", 0.0 * flx_fwd) # flx_plg.write(spec, file_emisincrout, flx_tl) # New make_fluxes function by J.C.A. van Peet
[docs] def make_fluxes(self, datastore, runsubdir, datei, mode): """ PURPOSE Make emission file for TM5 ARGS self (pycif.utils.classes.fluxes.Flux) = Flux plugin with all attributes datastore (dict) = information on flux species runsubdir (str) = directory to the current run nho (int) = number of hours in the run mode (str) = running mode: 'fwd', 'tl' or 'adj' NOTE This function calls the function self.flux.write, which is defined in pycif/plugins/fluxes/tm5/write.py VERSION HISTORY 2.2 21-10-2021 by J.C.A. van Peet Updated writing of fluxes. 2.1 20-07-2021 by J.C.A. van Peet *) Added the "adj" mode to cases when to write emissions. 2.0 21-05-2021 by J.C.A. van Peet Adapted for TM5. 1.0 20-05-2021 by A. Berchet See original code above. """ # Set the name of this function PROG_NAME = MODULE_NAME+".make_fluxes" # Local logger logger = logging.getLogger(PROG_NAME) logger.setLevel(logging.DEBUG) # Some debug statements... logger.debug("") logger.debug("*"*30) logger.debug(PROG_NAME+" => DEBUG:") logger.debug(" self = %s", self ) logger.debug(" data = %s", datastore ) logger.debug(" runsubdir = %s", runsubdir) logger.debug(" datei = %s", datei ) logger.debug(" mode = %s", mode ) # If you ever need the prior fluxes, see original code above. # Get the flux datastore flx_datastore = datastore[("flux", "CH4")] flx_data = datastore[("flux", "CH4")]["data"][datei] # Now you need to dump the updated fluxes for the present iteration # PyShell.em.filename to be set to emission.nc4 # JvP 20210720: added 'adj' to the mode-list in the if-statement below. # JvP 20211021: In addition to the emissions of the current iteration for # the adjoint run, I also need the a-priori fluxes to convert # the adj_emission.nc4 emission factors into actual emissions # (see native2inputs_adj.py). And since there is no TL model # for TM5, I'd rather issue a runtime warning then continue. # To solve these issues, rewrote the if-statement below. # #if "spec" in flx_datastore and mode in ["fwd", "tl", "adj"]: # # # Set current iteration flux file, and write it to file. # # The write function is defined in pycif/plugins/fluxes/tm5/write.py # #iter_flx = "{}/iter_emissions.nc".format(runsubdir) # iter_flx = "{}/emission.nc4".format(runsubdir) # logger.debug(" iter_flx = %s", iter_flx ) # self.flux.write("CH4", iter_flx, flx_datastore["spec"]) # ## end if # if "spec" in flx_data: if mode in ["fwd", "adj"]: # Set current iteration flux file, and write it to file. # The write function is defined in pycif/plugins/fluxes/tm5/write.py iter_flx = f"{runsubdir}/emission.nc4" logger.debug(f" mode = {mode}" ) logger.debug(f" iter_flx = {iter_flx}" ) self.flux.write("CH4", iter_flx, flx_data["spec"]) # Create a link to the prior flux file for the adjoint run. # Note: this file is read in # .../pycif/plugins/models/TM5/io/native2inputs_adj.py # so if you ever change the name here, you also have to change it # there. if mode == "adj": ref_aprior = f"{flx_datastore['dirorig']}/{flx_datastore['fileorig']}" target_prior = f"{runsubdir}/prior_emissions.nc4" path.link(ref_aprior, target_prior) # end if elif mode == "tl": logger.critical("") logger.critical("*"*30) logger.critical(PROG_NAME+" => ERROR: mode 'tl' not implemented in TM5!") logger.critical("*"*30) logger.critical("") raise CifRuntimeError else: logger.critical("") logger.critical("*"*30) logger.critical(PROG_NAME+" => ERROR: unknown value for 'mode'!") logger.critical(f" mode = {mode}") logger.critical("*"*30) logger.critical("") raise CifRuntimeError # end if mode else: logger.critical("") logger.critical("*"*30) logger.critical(PROG_NAME+" => ERROR: no 'spec' present in flx_datastore!") logger.critical("*"*30) logger.critical("") raise CifRuntimeError # end if ( "spec" in flx_datastore ) # Do the same for the increments if TL computation if "incr" in flx_data and mode in ["tl"]: # Set current increment flux file, and write it to file. # The write function is defined in pycif/plugins/fluxes/tm5/write.py incr_flx = f"{runsubdir}/incr_emissions.nc" logger.debug(" incr_flx = %s", incr_flx ) self.flux.write("CH4", incr_flx, flx_data["incr"]) # This if-statement was already present in the original code # (see above), but I don't know yet how to implement an # "increment flux file" for TM5, so I issue an error and see # when CIF crashes:) logger.critical("") logger.critical("*"*30) logger.critical(PROG_NAME+" => ERROR: don't know how increment flux file is implemented in TM5!") logger.critical("*"*30) logger.critical("") raise CifRuntimeError # end if # ... final debug statements ... logger.debug("*"*30) logger.debug("")
#logger.debug("") #logger.debug("*"*30) #logger.debug(PROG_NAME+" => Computer says no!") #logger.debug("*"*30) #logger.debug("") #try: # raise RuntimeError #except RuntimeError as e: # #logger.exception("OOPS!") # logger.critical(e, exc_info=True) # #raise # => Will display the traceback on screen a second time # sys.exit() # => Just exit. ## end try # end function make_fluxes