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)