Source code for pycif.plugins.models.iconart.io.inputs.make_auxiliary

import xarray as xr
import numpy as np
import os
import glob
import xml.etree.ElementTree as etree
from logging import debug
from .namelist import update_namelist
from .lbc import dump_lbc_files
from .inicond import dump_inicond_file
from ......utils.check.errclass import CifAttributeError

from ......utils import path
from ......utils.hdf5 import _hdf5_lock
from ..utils import (
    DYN_GRID_FILENAME,
    EXTPAR_FILENAME,
    LBC_GRID_FILENAME,
    RAD_GRID_FILENAME,
)


[docs] def make_auxiliary(self, ddi, runsubdir, do_simu=True, mode="fwd", **kwargs): """ Initialize every file or information needed by the model to run, excluding data that are initialized through the function ``native2inputs``. This includes name lists for Fortran, configuration files, etc. Every basic files related to the model should be first initialized in ``self.workdir/model`` at the initialization step in the function ``compile``. Hereafter, files are link/copied to ``runsubdir`` from the reference ones in ``self.workdir/model`` Note: For configuration files, one should follow the following basic rules: - paths expected by the model should always point to the current ``runsubdir``; thus the executable should be linked or copied in ``runsubdir``; in addition, every extra file should be link with a fixed name and the corresponding name should be given in the name-list or configuration file. - as many model parameters should be easily modified through the yaml configuration file; however, for some reasons, it may be preferable to limit the possibilities for pyCIF by keeping some parameters fixed; this question is up to the developer implementing one model Args: self: the model plugin ddi (datetime.datetime): the start data identifying the present simulation period runsubdir (str): path to the current sub-simulation work directory do_simu (bool): if False, the simulation does not need to be run, hence, in principle, no auxiliary data needs to be initialized mode (str): the running mode to compute """ # Otherwise initialize auxiliary info debug( f"Initializing auxiliary information for the model {self.plugin.name}/{self.plugin.version} with parameters: \n self: {self}\n ddi: {ddi}\n runsubdir: {runsubdir}\n do_simu: {do_simu}\n mode: {mode}\n") # -------------------------------------------------------- # Create links for important files # -------------------------------------------------------- # Grid files path.link( self.domain.dynamics_grid, os.path.join(runsubdir, DYN_GRID_FILENAME) ) path.link( self.domain.map_file, os.path.join(runsubdir, 'map_file.latbc') ) path.link( self.domain.extpar_file, os.path.join(runsubdir, EXTPAR_FILENAME) ) # Grid for lateral boundary conditions if hasattr(self.domain, "lbc_grid"): path.link( self.domain.lbc_grid, os.path.join(runsubdir, LBC_GRID_FILENAME) ) # Coarser grid for reduced radiation if hasattr(self.domain, "reduced_radiation_grid"): path.link( self.domain.reduced_radiation_grid, os.path.join(runsubdir, RAD_GRID_FILENAME) ) # Dictionary for the mapping: DWD GRIB2 names <-> ICON internal names path.link( os.path.join(self.icon_dir, 'run', 'ana_varnames_map_file.txt'), os.path.join(runsubdir, 'map_file.ana') ) art_dir = os.path.join(self.icon_dir, 'externals', 'art') for p in glob.glob(os.path.join(art_dir, 'runctrl_examples', 'photo_ctrl', '*')): path.link(p, os.path.join(runsubdir, os.path.basename(p))) for p in glob.glob(os.path.join(art_dir, 'runctrl_examples', 'init_ctrl', '*')): path.link(p, os.path.join(runsubdir, os.path.basename(p))) # Icon executable and wrapper if not hasattr(self, 'icon_exe'): raise CifAttributeError('icon_exe attribute not found.' 'You need to specify a path to ICON executable ' 'in the model Plugin.') path.link( os.path.join(self.icon_exe), os.path.join(runsubdir, 'icon.exe') ) path.link( os.path.join(os.path.dirname(self.icon_exe), '..', 'run/run_wrapper/todi_gpu.sh'), os.path.join(runsubdir, 'wrapper_icon.sh') ) # -------------------------------------------------------- # Dump the OEM ensemble files for fluxes and lbc # -------------------------------------------------------- # Create the lambdas file for fluxes fl = self.flux_lambdas[ddi] if len(fl) != 0: oem_dir = os.path.join(runsubdir, 'OEM') # Retrieve the dimensions nsamples, nreg = fl[list(fl.keys())[0]].shape[0:2] ntracers = len(self.chemistry.oem_tracers) ncat = len(self.chemistry.oem_categories) # Create the lambdas DataArray da_flux_lambdas = xr.DataArray( data=np.ones((nsamples, nreg, ncat, ntracers)), dims=("ens", "reg", "cat", "tracer") ) # Fill the DataArray with the pre-calculated scaling factors for ispec, spec in enumerate(self.chemistry.oem_tracers): for iemspec, emspec in enumerate(self.chemistry.oem_categories): if emspec in self.chemistry.mapping_active2emi_ref[spec]: da_flux_lambdas[:, :, iemspec, ispec] = fl[emspec] # Dump the DataArray ds_flux_lambdas = da_flux_lambdas.to_dataset(name='lambda') flux_lambdas_filepath = os.path.join(oem_dir, 'ens_lambda.nc') with _hdf5_lock: ds_flux_lambdas.to_netcdf(flux_lambdas_filepath) # Create the scaling regions file for fluxes flux_ens_regions_filepath = os.path.join(oem_dir, 'ens_reg.nc') # Create the mapping from (icon grid indexes) to (lambda regions in ensemble files) da_flux_reg_map = xr.DataArray( np.arange(1, self.domain.nlon + 1), dims=("cell") ) ds_flux_reg_map = da_flux_reg_map.to_dataset(name='REG') # Create the mapping from (16 VPRM flux cat + the cats in tracers.xml) to (lambda cat in ensemble file) ncat_vprm = 16 da_flux_cat_map = xr.DataArray( np.ones(ncat_vprm + da_flux_lambdas.shape[2]), dims=("cat") ) for iemspec, emspec in enumerate(self.chemistry.oem_categories): da_flux_cat_map[ncat_vprm + iemspec] = iemspec + 1 ds_flux_cat_map = da_flux_cat_map.to_dataset( name='Lambda_indicies') # ... variable name must be improved ds_flux_reg = xr.merge([ds_flux_reg_map, ds_flux_cat_map]) with _hdf5_lock: ds_flux_reg.to_netcdf(flux_ens_regions_filepath) # Create the lambdas file for lbc if len(self.lbc_lambdas[ddi]) != 0: oem_dir = os.path.join(runsubdir, 'OEM') for spec in self.lbc_lambdas[ddi]: lbc_lambdas = xr.DataArray( self.lbc_lambdas[ddi][spec], dims=("ens", "reg") ) lbc_lambdas = lbc_lambdas.to_dataset(name='lambda') lbc_lambdas_filepath = os.path.join(oem_dir, 'boundary_lambda.nc') with _hdf5_lock: lbc_lambdas.to_netcdf(lbc_lambdas_filepath) del self.flux_lambdas[ddi] del self.lbc_lambdas[ddi] # -------------------------------------------------------- # Dump the input file for inicond # -------------------------------------------------------- if hasattr(self, "dict_inicond_dataout"): if ddi in self.dict_inicond_dataout: dump_inicond_file(self, ddi, runsubdir) # -------------------------------------------------------- # Dump the input files for lbc # -------------------------------------------------------- if hasattr(self, "dict_lbc_dataout"): if ddi in self.dict_lbc_dataout: dump_lbc_files(self, ddi, runsubdir) # -------------------------------------------------------- # Dump the tracers.xml # -------------------------------------------------------- TYPES_TAGS_XML = { 'transport': 'char', 'unit': 'char', 'c_solve': 'char', 'oem_type': 'char', 'oem_bg_ens': 'char', 'oem_cat': 'char', 'oem_vp': 'char', 'oem_tp': 'char', 'oem_tscale': 'int', 'init_mode': 'int', 'init_name': 'char', 'latbc': 'char', 'iconv': 'int', 'iturb': 'int', } # Load the existing tracers.xml file xml_root = etree.Element('tracers') # Add active species to the tracers.xml file for spec, dtr_s in self.chemistry.dict_tracers.items(): xml_tracer = etree.SubElement(xml_root, 'chemtracer', { 'id': dtr_s['id'], 'id_cif': spec}) if 'oem_cat' in dtr_s and isinstance(dtr_s['oem_cat'], list): dtr_s['oem_cat'] = ','.join(sorted(dtr_s['oem_cat'])) dtr_s['oem_vp'] = ','.join(sorted(dtr_s['oem_vp'])) dtr_s['oem_tp'] = ','.join(sorted(dtr_s['oem_tp'])) for key, value in dtr_s.items(): if key != 'id': tag = etree.SubElement(xml_tracer, key, {'type': TYPES_TAGS_XML[key]}) tag.text = value # Save the xml with the correct headers tree = etree.ElementTree(xml_root) etree.indent(tree) tracers_xml_file = os.path.join(runsubdir, 'tracers.xml') tree.write(tracers_xml_file) with open(tracers_xml_file, 'r+') as f: content = f.read() f.seek(0, 0) f.write( '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE tracers SYSTEM "tracers.dtd">\n\n' + content) # -------------------------------------------------------- # Update the namelist # -------------------------------------------------------- update_namelist(self, ddi, runsubdir)