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