Source code for pycif.plugins.models.TM5.run

import os
import errno # used in silent_remove
import sys
from datetime import datetime, timedelta
import shutil
import subprocess
import glob

# Logging functions in order of increasing severity:
#    debug, info, warning, error, critical
# A local logger instance is used in run(...) for development purposes, but
# it could also be initialised after the import statement. More info:
# *) https://docs.python.org/3.7/library/logging.html
# *) https://docs.python.org/3.7/howto/logging.html
# *) https://stackoverflow.com/a/48787602
import logging

# JvP 20210202: defined MODULE_NAME and module logger
MODULE_NAME = __name__[__name__.index('TM5'):] if 'TM5' in __name__ else __name__
logger      = logging.getLogger(MODULE_NAME)

# JvP 20210723: added import of netCDF and numpy
import netCDF4 as nc4
import numpy as np


[docs] def silent_remove(filename): """ PURPOSE Delete a file without raising an exception if it doesn't exist. IN/OUT filename = string with the filename to remove. VERSION CHANGE HISTORY 1.1 02-02-2021 by J.C.A. van Peet. *) Added PROG_NAME *) Used new PROG_NAME as local logger name. 1.0 09-11-2020 by J.C.A. van Peet. Copied from https://stackoverflow.com/a/10840586, changed function name from silentremove to silent_remove. """ # JvP 20210202: Added PROG_NAME and local logger PROG_NAME = MODULE_NAME+".silent_remove" logger = logging.getLogger(PROG_NAME) try: os.remove(filename) except OSError as e: # this would be "except OSError, e:" before Python 2.6 if e.errno != errno.ENOENT: # errno.ENOENT = no such file or directory # JvP 20210202: added the logger.critical statement. The exception # info and traceback should now also be written to logfile. logger.critical(e, exc_info=True) raise # re-raise exception if a different error occurred
# end if # end try-except # end function silent_remove
[docs] def run(self, runsubdir, mode, workdir, ddi, do_simu=True, **kwargs): """ PURPOSE Call this function to run the TM5 model. I'm not sure which module does call this function... The order appears to be to first call compile.py, then params.py and then the current function... IN/OUT runsubdir = working directory for the current run (str) mode = forward or backward (str) workdir = pyCIF working directory (str) KWARGS none ASSUMPTIONS none EXCEPTIONS When this function encounters a problem that it cannot solve, it will raise a RuntimeError. Pythons exeception handling will provide a traceback, including files, calls and line numbers. PYTHON VERSION 3.7.6 VERSION CHANGE HISTORY 2.1 22-10-2021 by J.C.A. van Peet. Writing point departure files has been moved by Antoine to the module .../plugins/models/TM5/io/inputs/make_obs.py which makes use of functions that have been moved from the current run.py module to .../plugins/models/TM5/io/utils/point_data.py 2.0 23-07-2021 by J.C.A. van Peet. *) Added calculation of point departure file. 1.2 02-02-2021 by J.C.A. van Peet. *) Updated PROG_NAME *) Used new PROG_NAME as local logger name. 1.1 18-01-2021 by J.C.A. van Peet. Renamed tm5.exe to tm5.x 1.0 09-11-2020 by J.C.A. van Peet. Original code. """ # if mode in ["fwd", "tl"]: # # Keeps the running directory in memory for later adjoint # # simulations # self.adj_refdir = "{}/../".format(runsubdir) if not do_simu: return # Name of the program PROG_NAME = MODULE_NAME+".run" # Local logger # Logging functions in order of increasing severity: # debug, info, warning, error, critical # See https://stackoverflow.com/a/48787602 and import statement above for # more info. # Notes: # *) you do not need a verbosity variable ("verb") anymore, nor # "if( verb ):" statements. # *) to get the local level value and name, use # logger.critical("Local logging level = "+str(logger.level)) # logger.critical("Local logging name = "+str(logging.getLevelName(logger.level)) ) # *) to get the global level value and name, use # logger.critical("Global logging level = "+str(logging.getLogger().level)) # logger.critical("Global logging name = "+str(logging.getLevelName(logging.getLogger().level)) ) logger = logging.getLogger(PROG_NAME) logger.setLevel(logging.DEBUG) # Lowest level possible # ************************************ # * NO MORE SETTINGS BELOW THIS LINE * # ************************************ # Start message logger.debug("") logger.debug(PROG_NAME+" => start") # Print the Wall Time Before Run wtbr = datetime.now() logger.debug(PROG_NAME+" => wall time before run = "+wtbr.strftime("%Y-%m-%dT%H:%M:%S")) # Debug information logger.info (PROG_NAME+" => info") logger.info (" runsubdir = %s" % (runsubdir) ) logger.info (" mode = %s" % (mode ) ) logger.info (" workdir = %s" % (workdir ) ) # Remove already existing log and ok files silent_remove("{}/tm5.ok".format(runsubdir)) silent_remove("{}/tm5.log".format(runsubdir)) # Run TM5 # JvP 20210118: renamed tm5.exe to tm5.x tm5_logfile = "{}/tm5.log".format(runsubdir) logger.info(PROG_NAME+" => Running sub-simulation in {}".format(runsubdir)) logger.info(PROG_NAME+" => Writing TM5 log to "+tm5_logfile) with open(tm5_logfile, "w") as log: process = subprocess.Popen( ["{}/tm5.x".format(runsubdir), "tm5.rc"], cwd=runsubdir, stdout=log, stderr=subprocess.PIPE ) _, stderr = process.communicate() # end with # Raise exception if TM5 did not run successfully. if stderr != "" and not os.path.isfile("{}/tm5.ok".format(runsubdir)): logger.info("") logger.info("*"*30) logger.info(PROG_NAME+" => TM5 did not run properly in {}".format(runsubdir)) logger.info("stderr follows:") logger.info(str(stderr, "utf-8")) logger.info("*"*30) logger.info("") raise RuntimeError # end if # Print the Wall Time After Run wtar = datetime.now() logger.debug(PROG_NAME+" => wall time after run = "+wtar.strftime("%Y-%m-%dT%H:%M:%S")) logger.debug(PROG_NAME+" => wall time delta = %s" % (wtar-wtbr) ) # JvP 20211022 # Writing point departure files has been moved by Antoine to the module # .../plugins/models/TM5/io/inputs/make_obs.py # which makes use of functions that have been moved from the current # run.py module to # .../plugins/models/TM5/io/utils/point_data.py # Stop message logger.debug(PROG_NAME+" => stop") 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 run