Source code for pycif.plugins.models.wrfchem.io.outputs.read_sim

import os
import logging
import glob
import bisect
import copy
import pandas as pd
import numpy as np
import netCDF4 as nc
import datetime as dtm
from ......utils.check.errclass import CifFileNotFoundError, CifRuntimeError


[docs] def read_sim(self, data2dump, runsubdir, mode, ddi, ddf): """Read simulated observations from WRF-Chem output""" # This borrows from CTDAS-WRF # First, check whether there is anything to do. if mode != "fwd": raise CifRuntimeError("Only works with mode 'fwd'") # Prepare a bit for multiple domains, but work only with one domain # for now wrfout_files = dict() wrfout_start_dtm_ids = dict() dom = 1 # Get wrfout files fp_pattern = os.path.join(runsubdir, f"wrfout_d{dom:02d}_*00") wrfout_files[dom] = glob.glob(fp_pattern) if len(wrfout_files[dom]) == 0: raise CifFileNotFoundError("No WRF output found.") wrfout_files[dom] = np.sort(wrfout_files[dom]).tolist() _, wrfout_start_dtm_ids[dom] = \ self.wrfhelper.wrf_times(wrfout_files[dom]) dataout = {} for trid in data2dump: spec = trid[1] dat = self.dataobs[ddi][spec] # Get spatial indices for sampling iv = np.round(np.array(dat[("metadata", "i")])).astype(int) jv = np.round(np.array(dat[("metadata", "j")])).astype(int) # During development, the wrf domain changed from structured to unstructured. # Here, we unravel the indices in case we have the unstructured version. if self.domain.unstructured_domain: iv, jv = np.unravel_index(iv, self.domain.zlon2d.shape) levelv = np.round(np.array(dat[("metadata", "level")])).astype(int) # Get files and time index in file from tstep for sampling ind_all_t = dat["metadata"]["tstep"].values ind_f = [bisect.bisect_right(wrfout_start_dtm_ids[dom], ind_t) - 1 for ind_t in ind_all_t] files = [wrfout_files[dom][ind_f_] for ind_f_ in ind_f] ind_t_file = [ind_t - wrfout_start_dtm_ids[dom][ind_f_] for ind_t, ind_f_ in zip(ind_all_t, ind_f)] loc_ll = zip(files, ind_t_file) # This line is slow: loc = pd.DataFrame(loc_ll, columns=["file", "ind_t"]) # Now that all the information for sampling is collected, read # data from wrfout files. # For vectorized indexing, have to read full netcdf output. # Therefore looping over timesteps with data, as some may not # have any. Perhaps this can be sped up, e.g. with xarray. loc["value"] = np.nan if trid[0] in ["pressure", "dpressure"]: ptop = float(self.namelist["domains"]["p_top_requested"]) # Pa loc["psfc"] = -999. if trid[0] in ["concs"]: varname = getattr(getattr(self.chemistry.acspecies, spec), "varname") UF = list(set(loc["file"])) for f in UF: ind_f = np.where(loc["file"] == f)[0] ncf = nc.Dataset(f, "r") UIT = list(set(loc.loc[ind_f, "ind_t"])) for it in UIT: ind = ind_f[np.where(loc.loc[ind_f, "ind_t"] == it)[0]] if trid[0] in ["concs"]: field = ncf[varname][it, ...] loc.loc[ind, "value"] = field[levelv[ind], iv[ind], jv[ind]] # Get surface pressure (for pressure # midpoints/layer thicknesses) if trid[0] in ["pressure", "dpressure"]: psfc = ncf["PSFC"][it, ...] # Pa loc.loc[ind, "psfc"] = psfc[iv[ind], jv[ind]] ncf.close() # Compute pressure midpoints/layer thicknesses from surface pressure if trid[0] in ["pressure", "dpressure"]: if trid[0] in ["pressure"]: loc["value"] = \ self.domain.sigma_a_mid[levelv] + loc["psfc"].values*self.domain.sigma_b_mid[levelv] if trid[0] in ["dpressure"]: loc["value"] = \ (self.domain.sigma_a[levelv] + loc["psfc"].values*self.domain.sigma_b[levelv]) \ -(self.domain.sigma_a[levelv+1] + loc["psfc"].values*self.domain.sigma_b[levelv+1]) del loc["psfc"] # Write values to output variable dat[("maindata", "spec")] = loc["value"].values # This is copied from chimere: if trid[0] in ["pressure", "dpressure"]: dat[("maindata", "incr")] = 0. dataout[trid] = dat return dataout