Source code for jobs.tools.camchem_ic_lbc_reggrid

#!/usr/bin/env python3

import os
from os.path import join
from netCDF4 import Dataset
from .nc_operations import VariableCreator, VariableCopier, DimensionCopier
from .. import tools


[docs] def process_ic(file_path_in, file_path_out, ic_datetime, aero_dict, prefix): """ Generate initial condition (IC) NetCDF files from CAM-Chem output. This function copies chemical and aerosol fields for a specified datetime from an input CAM-Chem NetCDF file. Aerosol fields can be split into different modes. No unit transformation is performed. Parameters ---------- file_path_in : str Path to the input directory containing CAM-Chem NetCDF files. file_path_out : str Path to the output directory where IC files will be saved. ic_datetime : datetime.datetime Datetime for the IC to process. aero_dict : dict Dictionary specifying how aerosol variables should be split into modes and their corresponding fractions. Format: `{aerosol_var_name: {mode_name: split_fraction, ...}, ...}`. prefix : str Filename prefix for input and output NetCDF files. Returns ------- None Notes ----- - Input files are expected to follow the naming convention: `{prefix}%Y%m%d%H.nc`. - Output files are saved as `{prefix}%Y%m%d%H_ic.nc`. - Variables not present in `aero_dict` are copied directly. - Aerosol variables are split according to the fractions defined in `aero_dict`. """ in_template = prefix + '%Y%m%d%H.nc' outname_template = prefix + '%Y%m%d%H_ic.nc' in_filename = ic_datetime.strftime(in_template) out_filename = ic_datetime.strftime(outname_template) in_path = join(file_path_in, in_filename) with Dataset(in_path, 'r') as ds: # -- Create output filename out_path = join(file_path_out, out_filename) # -- Write output netCDF file containing IC with Dataset(out_path, 'w') as out_ds: # -- Copy global attributes out_ds.setncatts(ds.__dict__) # -- Copy dimensions dimpairs = [(dim_name, dim_name) for dim_name, dim in ds.dimensions.items()] dim_copier = [ DimensionCopier(src_name, dst_name) for src_name, dst_name in dimpairs ] # -- Copy variables var_to_copy = [ var_name for var_name, v in ds.variables.items() if var_name not in aero_dict ] dict_var = [{ 'src_names': var, 'dst_name': var } for var in var_to_copy] var_copier = [VariableCopier(**kwargs) for kwargs in dict_var] for op in dim_copier + var_copier: op.apply_to(ds, out_ds) # -- Split aerosols into modes for var_name, modes_dict in aero_dict.items(): for mode_name, split in modes_dict.items(): var_mmr = ds[var_name][:] * split (VariableCreator(var_args={ 'varname': mode_name, 'datatype': 'f8', 'dimensions': ('time', 'lev_m', 'lat', 'lon') }, var_attrs={ 'long_name': mode_name + ' mass mixing ratio', 'units': 'kg/kg' }, var_vals=var_mmr).apply_to(out_ds))
########################################
[docs] def process_lbc(file_path_in, file_path_out, start_time, end_time, inc, prefix, suffix, nameformat, var_mw_dict, aero_dict): """ Generate lateral boundary condition (LBC) NetCDF files from CAM-Chem output. This function processes CAM-Chem NetCDF files and produces LBC files with appropriate unit transformations. Chemical fields are converted from [mol/mol] to [kg/kg], while aerosol fields are split into modes and converted from [kg/kg] to [μg/kg]. Parameters ---------- file_path_in : str Path to the input directory containing CAM-Chem NetCDF files. file_path_out : str Path to the output directory where LBC files will be saved. start_time : datetime.datetime Start datetime for the LBC processing range. end_time : datetime.datetime End datetime for the LBC processing range. inc : int Time increment in hours between consecutive files to process. prefix : str Filename prefix used for both input and output files. suffix : str Filename suffix used for both input and output files (e.g., '.nc'). nameformat : str Datetime format string used in the filenames (e.g., '%Y%m%d%H'). var_mw_dict : dict Dictionary mapping chemical variable names to their molecular weights for unit conversion. Format: `{var_name: molecular_weight, ...}`. aero_dict : dict Dictionary specifying how aerosol variables should be split into modes and their corresponding fractions. Format: `{aerosol_var_name: {mode_name: split_fraction, ...}, ...}`. Returns ------- None Notes ----- - Input files are iterated over using specified increments between `start_time` and `end_time`. - Chemical fields are converted from [mol/mol] to [kg/kg] using the molecular weight of air (28.96 g/mol) and the variable-specific molecular weight. - Aerosol fields are split into modes and converted from [kg/kg] to [μg/kg]. - Essential variables like coordinates and pressure are copied directly - Output files are saved with `_lbc` appended to the original filename. """ for time in tools.iter_hours(start_time, end_time, inc): # -- Extract datetime information from the filename in_file = os.path.join(file_path_in, time.strftime(prefix + nameformat + suffix)) with Dataset(in_file, 'r') as ds: # -- Create output filename out_filename = time.strftime(prefix + nameformat + '_lbc' + suffix) out_file = join(file_path_out, out_filename) # -- Write output netCDF file containing LBC with Dataset(out_file, 'w') as out_ds: ## Global attributes out_ds.setncatts(ds.__dict__) # -- Copy dimensions dimpairs = [(dim_name, dim_name) for dim_name, dim in ds.dimensions.items()] dim_copier = [ DimensionCopier(src_name, dst_name) for src_name, dst_name in dimpairs ] # -- Copy variables var_to_copy = [ 'lev_s', 'lev_m', 'lon', 'lat', 'hyam', 'hybm', 'hyai', 'hybi', 'time', 'date', 'datesec', 'PS' ] dict_var = [{ 'src_names': var, 'dst_name': var } for var in var_to_copy] var_copier = [VariableCopier(**kwargs) for kwargs in dict_var] for op in dim_copier + var_copier: op.apply_to(ds, out_ds) # -- Transform units [mol/mol] --> [kg/kg] of chemical fields # Molar weight air mw_air = 28.96 for var_name, mw in var_mw_dict.items(): # [mol/mol] --> [kg/kg] var_mmr = ds[var_name][:] * mw / mw_air (VariableCreator(var_args={ 'varname': var_name, 'datatype': 'f8', 'dimensions': ('time', 'lev_m', 'lat', 'lon') }, var_attrs={ 'long_name': var_name + ' mass mixing ratio', 'units': 'kg/kg' }, var_vals=var_mmr).apply_to(out_ds)) # -- Split aerosols into modes and transform units [kg/kg] --> [ug/kg] kg_to_mug = 1.e9 for var_name, modes_dict in aero_dict.items(): for mode_name, split in modes_dict.items(): # [kg/kg] --> [ug/kg] var_mmr = ds[var_name][:] * split * kg_to_mug (VariableCreator(var_args={ 'varname': mode_name, 'datatype': 'f8', 'dimensions': ('time', 'lev_m', 'lat', 'lon') }, var_attrs={ 'long_name': mode_name + ' mass mixing ratio', 'units': 'mug/kg' }, var_vals=var_mmr).apply_to(out_ds))
########################################