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

import pandas as pd
import datetime
import os
import shutil
import subprocess
import glob
import numpy as np
from pathlib import Path

from logging import info

from .flushrun import flush_rundir
from .utils import check_inputs

from .io.outputs.read_sim import readend, readmeteo, read_obs, write_sim, write_obs
from .io.outputs.fetch_end import make_end, make_aend
from .io.outputs.make_aout import make_aout


[docs]def run(self, runsubdir, mode, workdir, ddi, nbproc=1, do_simu=True, approx_transf=False, ref_fwd_dir="", overlap=False, **kwargs): """Run the CHIMERE model in forward mode Args: self: the model Plugin runsubdir (str): working directory for the current run mode (str): forward or backward workdir (str): pyCIF working directory do_simu (bool): re-run or not existing simulation """ # Check mode if mode not in ["fwd", "tl", "adj"]: raise Exception("Unknown mode {} for CHIMERE execution".format(mode)) # Resetting observation flag for updating obs.txt self.iniobs[ddi] = False self.reset_obs[ddi] = True if not do_simu: # if mode in ["fwd", "tl"]: # # Keeps the running directory in memory for later adjoint # # simulations # self.adj_refdir = "{}/../".format(runsubdir) return # Cleaning the directory shutil.rmtree("{}/mod.txt".format(runsubdir), ignore_errors=True) # Number of processors nbproc = str(self.nzdoms * self.nmdoms + 1) nho = self.nho list_spec_stop = self.list_spec_stop list_thld_stop = self.list_thld_stop actual_run = self.runsimu[ddi] if actual_run and not approx_transf: # In adjoint mode, setting sensitivities to zero if overlap period if mode == "adj" and overlap: obs_scheme = read_obs(runsubdir, mode="adj") write_obs(obs_scheme, runsubdir) # Check that inputs have been correctly created check_inputs(self, runsubdir, mode) # Running the model info("Running sub-simulation in {}".format(runsubdir)) with open("{}/chimere.log".format(runsubdir), "w") as log: process = subprocess.Popen( [self.mpirun] + self.run_options + ["{}/chimere.e".format(runsubdir)], cwd=runsubdir, stdout=log, stderr=subprocess.PIPE ) _, stderr = process.communicate() if not os.path.isfile("{}/all_good".format(runsubdir)): info("Exception in CHIMERE") info(str(stderr, "utf-8")) raise Exception( "CHIMERE did not run properly in {}".format(runsubdir) ) elif stderr != "": with open("{}/chimere.errlog".format(runsubdir), "w") as f: f.write(str(stderr, "utf-8")) if mode in ["fwd", "tl"]: if list_spec_stop: # stopORmore activated # generally in case of computing response fucntions # test to stop if concentrations are all small enough list_spec_end, conc_end = readend( '{}/end.nc'.format(runsubdir)) # conversion from molec.cm-3 to ppb: /(airm[0,l,i,j]*1e-9) airm = readmeteo('{}/METEO.nc'.format(runsubdir), ['airm'])[0] nspresc = self.chemistry.nprspecies stopcalc = True for spec in list_spec_end[:len(list_spec_end) - nspresc]: if spec in list_spec_stop: conc_end_ppb = np.divide( conc_end[list_spec_end.index(spec)], airm[int(nho), :, :, :]) conc_end_ppb = 1.e9 * conc_end_ppb maxspec = np.amax(conc_end_ppb) if maxspec > list_thld_stop[list_spec_stop.index(spec)]: stopcalc = False if stopcalc: info( 'STOPPING calculations because concentrations small enough ') # put all posterior dates to False for runsimu for dd in self.runsimu: if dd > ddi: self.runsimu[dd] = False # Putting all simulated concentrations to zero if overlap period if overlap: obs_scheme = read_obs(runsubdir) write_sim(obs_scheme, runsubdir) else: info("NOT running sub-simulation in {} " "due to choice of stopORmore function " "or approximating operator".format(runsubdir)) # Mimic all_good os.system("touch {}/all_good".format(runsubdir)) # Make artificial outputs if mode in ["fwd", "tl"]: # Mimic mod.txt (with 0 for the simulation) obs_scheme = read_obs(runsubdir) write_sim(obs_scheme, runsubdir) # Make empty end.nc for safe linking # For stopped simulation, just make random link if not actual_run: Path('{}/end.nc'.format(runsubdir)).touch() # Use end concentrations from reference forward directory else: make_end(self, '{}/end.nc'.format(runsubdir), ddi, ref_fwd_dir) else: # Make empty aend.nc for safe linking make_aend(self, '{}/aend.nc'.format(runsubdir), ddi) # Mimick empty aout files make_aout(self, runsubdir, ddi) # Process here initial conditions for the next simulation date = datetime.datetime.strptime( os.path.basename(runsubdir), "%Y-%m-%d_%H-%M" ) if mode in ["fwd", "tl"]: # move end.nc os.system( date.strftime( "mv -f {}/end.nc {}/../chain/end.%Y%m%d%H.{}.nc".format( runsubdir, runsubdir, nho ) ) ) elif mode == "adj": os.system( date.strftime( "mv -f {}/aend.nc {}/../chain/aend.%Y%m%d%H.{}.nc".format( runsubdir, runsubdir, nho ) ) ) # if mode in ["fwd", "tl"]: # # Keeps the running directory in memory for later adjoint simulations # self.adj_refdir = "{}/../".format(runsubdir) # Clean run subdirectory to avoid over-loading disks if self.force_clean_run: flush_rundir(runsubdir, mode)