MPTRAC
Functions
mptrac.c File Reference

MPTRAC library definitions. More...

#include "mptrac.h"

Go to the source code of this file.

Functions

void cart2geo (const double *x, double *z, double *lon, double *lat)
 State variables of cuRAND random number generator. More...
 
double clim_oh (const ctl_t *ctl, const clim_t *clim, const double t, const double lon, const double lat, const double p)
 Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal correction based on solar zenith angle. More...
 
void clim_oh_diurnal_correction (const ctl_t *ctl, clim_t *clim)
 Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data. More...
 
double clim_photo (const double rate[CP][CSZA][CO3], const clim_photo_t *photo, const double p, const double sza, const double o3c)
 Calculates the photolysis rate for a given set of atmospheric conditions. More...
 
double clim_tropo (const clim_t *clim, const double t, const double lat)
 Calculates the tropopause pressure based on climatological data. More...
 
void clim_tropo_init (clim_t *clim)
 Initializes the tropopause data in the climatology structure. More...
 
double clim_ts (const clim_ts_t *ts, const double t)
 Interpolates a time series of climatological variables. More...
 
double clim_zm (const clim_zm_t *zm, const double t, const double lat, const double p)
 Interpolates monthly mean zonal mean climatological variables. More...
 
void compress_log_level (FILE *out, const char *codec, const char *varname, const size_t lev, const double plev, const double ratio, const double bpv, const double t_comp, const double t_decomp, const size_t n, const size_t nbytes, const float *org, const float *cmp)
 Write one row of per-level compression diagnostics. More...
 
void compress_log_levels_3d (FILE *out, const char *codec, const char *varname, const met_t *met, const float *org_all, const float *cmp_all, const size_t nxy, const size_t nz, const double ratio, const double bpv, const double t_comp, const double t_decomp, const size_t nbytes)
 Write per-level compression diagnostics for a full 3-D field. More...
 
void compress_scale_to_unit (float *array, const size_t nxy, const size_t nz, double *off, double *scl)
 Scales each vertical level of a 3-D field independently to the interval [0,1]. More...
 
void compress_unscale_from_unit (float *array, const size_t nxy, const size_t nz, const double *off, const double *scl)
 Restores a levelwise [0,1]-scaled 3-D field to physical units. More...
 
int compress_read_lossy_scale (FILE *in, const size_t nz, double **off, double **scl)
 Read optional lossyscaling metadata for a 3-D field. More...
 
void compress_write_lossy_scale (FILE *out, const int enabled, float *array, const size_t nxy, const size_t nz, double **off, double **scl)
 Write optional lossyscaling metadata for a 3-D field. More...
 
int compress_metvar_index (const char *varname)
 Maps a meteorological variable name to its internal MPTRAC variable index. More...
 
void compress_pck (const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
 Compresses or decompresses a 3‑D float array using the PCK format. More...
 
double cos_sza (const double sec, const double lon, const double lat)
 Calculates the cosine of the solar zenith angle. More...
 
void day2doy (const int year, const int mon, const int day, int *doy)
 Get day of year from date. More...
 
void doy2day (const int year, const int doy, int *mon, int *day)
 Converts a given day of the year (DOY) to a date (month and day). More...
 
void fft_help (double *fcReal, double *fcImag, const int n)
 Computes the Fast Fourier Transform (FFT) of a complex sequence. More...
 
void geo2cart (const double z, const double lon, const double lat, double *x)
 Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates. More...
 
void get_met_filename (const ctl_t *ctl, const double t, const int direct, const char *metbase, const double dt_met, char *filename)
 Generates a formatted filename for meteorological data files based on the input parameters. More...
 
void get_met_replace (char *orig, const char *search, const char *repl)
 Replaces occurrences of a substring in a string with another substring. More...
 
void get_tropo (const int met_tropo, ctl_t *ctl, const clim_t *clim, met_t *met, const double *lons, const int nx, const double *lats, const int ny, double *pt, double *zt, double *tt, double *qt, double *o3t, double *ps, double *zs)
 Calculate tropopause data. More...
 
void intpol_check_lon_lat (const double *lons, const int nlon, const double *lats, const int nlat, const double lon, const double lat, double *lon2, double *lat2)
 Adjusts longitude and latitude to ensure they fall within valid bounds. More...
 
void intpol_check_cartesian (const double *lons, const int nlon, const double *lats, const int nlat, const double lon, const double lat, double *lon2, double *lat2)
 Clamps UTM coordinates to the valid bounds. More...
 
void intpol_met_4d_zeta (const met_t *met0, float heights0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float heights1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double height, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological variables to a given position and time. More...
 
void intpol_met_space_3d (const met_t *met, float array[EX][EY][EP], const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological variables in 3D space. More...
 
void intpol_met_space_2d (const met_t *met, float array[EX][EY], const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological variables in 2D space. More...
 
void intpol_met_time_3d (const met_t *met0, float array0[EX][EY][EP], const met_t *met1, float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological data in 3D space and time. More...
 
void intpol_met_time_2d (const met_t *met0, float array0[EX][EY], const met_t *met1, float array1[EX][EY], const double ts, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological data in 2D space and time. More...
 
void intpol_tropo_3d (const double time0, float array0[EX][EY], const double time1, float array1[EX][EY], const double lons[EX], const double lats[EY], const int nlon, const int nlat, const double time, const double lon, const double lat, const int method, double *var, double *sigma)
 Interpolates tropopause data in 3D (latitude, longitude, and time). More...
 
void jsec2time (const double jsec, int *year, int *mon, int *day, int *hour, int *min, int *sec, double *remain)
 Converts Julian seconds to calendar date and time components. More...
 
double kernel_weight (const double kz[EP], const double kw[EP], const int nk, const double p)
 Calculates the kernel weight based on altitude and given kernel data. More...
 
double lapse_rate (const double t, const double h2o)
 Calculates the moist adiabatic lapse rate in Kelvin per kilometer. More...
 
void level_definitions (ctl_t *ctl)
 Defines pressure levels for meteorological data. More...
 
int locate_irr (const double *xx, const int n, const double x)
 Locate the index of the interval containing a given value in a sorted array. More...
 
int locate_irr_float (const float *xx, const int n, const double x, const int ig)
 Locate the index of the interval containing a given value in an irregularly spaced array. More...
 
int locate_reg (const double *xx, const int n, const double x)
 Locate the index of the interval containing a given value in a regular grid. More...
 
void locate_vert (float profiles[EX][EY][EP], const int np, const int lon_ap_ind, const int lat_ap_ind, const double height_ap, int *ind)
 Locate the four vertical indizes of a box for a given height value. More...
 
void module_advect (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Advances particle positions using different advection schemes. More...
 
void module_advect_init (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Initializes the advection module by setting up pressure fields. More...
 
void module_bound_cond (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Apply boundary conditions to particles based on meteorological and climatological data. More...
 
void module_chem_grid (const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double tt)
 Computes gridded chemical tracer concentrations (volume mixing ratio) from individual air parcel mass data and assigns them back to the parcels. More...
 
void module_chem_init (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Initializes the chemistry modules by setting atmospheric composition. More...
 
void module_convection (const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Performs convective mixing of atmospheric particles. More...
 
void module_decay (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, atm_t *atm)
 Simulate exponential decay processes for atmospheric particles. More...
 
void module_diff_meso (const ctl_t *ctl, cache_t *cache, const met_t *met0, const met_t *met1, atm_t *atm)
 Simulate mesoscale diffusion for atmospheric particles. More...
 
void module_diff_pbl (const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Computes particle diffusion within the planetary boundary layer (PBL). More...
 
void module_diff_turb (const ctl_t *ctl, cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Applies turbulent diffusion processes to atmospheric particles. More...
 
void module_dry_depo (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Simulate dry deposition of atmospheric particles. More...
 
void module_h2o2_chem (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Perform chemical reactions involving H2O2 within cloud particles. More...
 
void module_isosurf_init (const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Initialize the isosurface module based on atmospheric data. More...
 
void module_isosurf (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Apply the isosurface module to adjust atmospheric properties. More...
 
void module_meteo (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Update atmospheric properties using meteorological data. More...
 
void module_mixing (const ctl_t *ctl, const clim_t *clim, atm_t *atm, const double t)
 Update atmospheric properties through interparcel mixing. More...
 
void module_mixing_help (const ctl_t *ctl, const clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, const int qnt_idx, const int use_ensemble)
 Perform subgrid-scale interparcel mixing of a given quantity. More...
 
void module_oh_chem (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Perform hydroxyl chemistry calculations for atmospheric particles. More...
 
void module_position (const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm, const int reflect)
 Update the positions and pressure levels of atmospheric particles. More...
 
void module_radio_decay (const ctl_t *ctl, const cache_t *cache, atm_t *atm)
 Apply radioactive decay to atmospheric tracer species. More...
 
void module_radio_depo (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm, depo_t *depo)
 Deposit supported radionuclides from air parcels onto the ground grid. More...
 
void module_rng_init (const int ntask)
 Initialize random number generators for parallel tasks. More...
 
void module_rng (const ctl_t *ctl, double *rs, const size_t n, const int method)
 Generate random numbers using various methods and distributions. More...
 
void module_sedi (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Simulate sedimentation of particles in the atmosphere. More...
 
void module_sort (const ctl_t *ctl, const met_t *met0, atm_t *atm)
 Sort particles according to box index. More...
 
void module_sort_help (double *a, const int *p, const int np)
 Reorder an array based on a given permutation. More...
 
void module_timesteps (const ctl_t *ctl, cache_t *cache, const met_t *met0, atm_t *atm, const double t)
 Calculate time steps for air parcels based on specified conditions. More...
 
void module_timesteps_init (ctl_t *ctl, const atm_t *atm)
 Initialize start time and time interval for time-stepping. More...
 
void module_tracer_chem (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Simulate chemical reactions involving long-lived atmospheric tracers. More...
 
void module_wet_depo (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Perform wet deposition calculations for air parcels. More...
 
void mptrac_alloc (ctl_t **ctl, cache_t **cache, clim_t **clim, met_t **met0, met_t **met1, atm_t **atm, depo_t **depo, dd_t **dd)
 Allocates and initializes memory resources for MPTRAC. More...
 
void mptrac_free (ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, depo_t *depo, dd_t *dd)
 Frees memory resources allocated for MPTRAC. More...
 
void mptrac_get_met (ctl_t *ctl, clim_t *clim, const double t, met_t **met0, met_t **met1, dd_t *dd)
 Retrieves meteorological data for the specified time. More...
 
void mptrac_init (ctl_t *ctl, cache_t *cache, clim_t *clim, atm_t *atm, depo_t *depo, const int ntask)
 Initializes the MPTRAC model and its associated components. More...
 
int mptrac_read_atm (const char *filename, const ctl_t *ctl, atm_t *atm)
 Reads air parcel data from a specified file into the given atmospheric structure. More...
 
void mptrac_read_clim (const ctl_t *ctl, clim_t *clim)
 Reads various climatological data and populates the given climatology structure. More...
 
void mptrac_read_ctl (const char *filename, int argc, char *argv[], ctl_t *ctl)
 Reads control parameters from a configuration file and populates the given structure. More...
 
int mptrac_read_met (const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met, dd_t *dd)
 Reads meteorological data from a file, supporting multiple formats and MPI broadcasting. More...
 
void mptrac_run_timestep (ctl_t *ctl, cache_t *cache, clim_t *clim, met_t **met0, met_t **met1, atm_t *atm, depo_t *depo, double t, dd_t *dd)
 Executes a single timestep of the MPTRAC model simulation. More...
 
void mptrac_update_device (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
 Updates device memory for specified data structures. More...
 
void mptrac_update_host (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
 Updates host memory for specified data structures. More...
 
void mptrac_write_atm (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes air parcel data to a file in various formats. More...
 
void mptrac_write_met (const char *filename, const ctl_t *ctl, met_t *met)
 Writes meteorological data to a file, supporting multiple formats and compression options. More...
 
void mptrac_write_output (const char *dirname, const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, depo_t *depo, const double t)
 Writes various types of output data to files in a specified directory. More...
 
double nat_temperature (const double p, const double h2o, const double hno3)
 Calculates the nitric acid trihydrate (NAT) temperature. More...
 
double pbl_weight (const ctl_t *ctl, const atm_t *atm, const int ip, const double pbl, const double ps)
 Computes a weighting factor based on planetary boundary layer pressure. More...
 
int read_atm_asc (const char *filename, const ctl_t *ctl, atm_t *atm)
 Reads air parcel data from an ASCII file and populates the given atmospheric structure. More...
 
int read_atm_bin (const char *filename, const ctl_t *ctl, atm_t *atm)
 Reads air parcel data from a binary file and populates the given atmospheric structure. More...
 
int read_atm_clams (const char *filename, const ctl_t *ctl, atm_t *atm)
 Reads atmospheric data from a CLAMS NetCDF file. More...
 
int read_atm_nc (const char *filename, const ctl_t *ctl, atm_t *atm)
 Reads air parcel data from a generic netCDF file and populates the given atmospheric structure. More...
 
void read_clim_photo (const char *filename, clim_photo_t *photo)
 Reads photolysis rates from a NetCDF file and populates the given photolysis structure. More...
 
void read_clim_photo_help (const int ncid, const char *varname, const clim_photo_t *photo, double var[CP][CSZA][CO3])
 Reads a 3D climatological photochemistry variable from a NetCDF file. More...
 
int read_clim_ts (const char *filename, clim_ts_t *ts)
 Reads a climatological time series from a file and populates the given time series structure. More...
 
void read_clim_zm (const char *filename, const char *varname, clim_zm_t *zm)
 Reads zonally averaged climatological data from a netCDF file and populates the given structure. More...
 
void read_kernel (const char *filename, double kz[EP], double kw[EP], int *nk)
 Reads kernel function data from a file and populates the provided arrays. More...
 
int read_met_bin (const char *filename, const ctl_t *ctl, met_t *met)
 Reads meteorological data from a binary file. More...
 
void read_met_bin_2d (FILE *in, const met_t *met, float var[EX][EY], const char *varname)
 Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array. More...
 
void read_met_bin_3d (FILE *in, const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname, const float bound_min, const float bound_max)
 Reads 3D meteorological data from a binary file, potentially using different compression methods. More...
 
void read_met_cape (const ctl_t *ctl, const clim_t *clim, met_t *met)
 Calculates Convective Available Potential Energy (CAPE) for each grid point. More...
 
void read_met_cloud (met_t *met)
 Calculates cloud-related variables for each grid point. More...
 
void read_met_detrend (const ctl_t *ctl, met_t *met)
 Detrends meteorological data. More...
 
void read_met_extrapolate (met_t *met)
 Extrapolates meteorological data. More...
 
void read_met_geopot (const ctl_t *ctl, met_t *met)
 Calculates geopotential heights from meteorological data. More...
 
void read_met_nc_grid (const char *filename, const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
 Reads meteorological grid data from NetCDF files with domain decomposition. More...
 
void read_met_nc_surface (const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
 Reads and processes surface meteorological data from NetCDF files with domain decomposition. More...
 
void read_met_nc_levels (const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
 Reads and processes meteorological level data from NetCDF files with domain decomposition. More...
 
int read_met_nc_2d (const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const char *varname5, const char *varname6, const ctl_t *ctl, const met_t *met, dd_t *dd, float dest[EX][EY], const float scl, const int init)
 Reads a 2-dimensional meteorological variable from a NetCDF file. More...
 
int read_met_nc_3d (const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const ctl_t *ctl, const met_t *met, dd_t *dd, float dest[EX][EY][EP], const float scl)
 Reads a 3-dimensional meteorological variable from a NetCDF file. More...
 
void read_met_ml2pl (const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname)
 Interpolates meteorological data to specified pressure levels. More...
 
void read_met_monotonize (const ctl_t *ctl, met_t *met)
 Makes zeta and pressure profiles monotone. More...
 
int read_met_nc (const char *filename, const ctl_t *ctl, met_t *met, dd_t *dd)
 Reads meteorological data from a NetCDF file and processes it. More...
 
void dd_read_met_nc_grid (dd_t *dd, const ctl_t *ctl, met_t *met, const int ncid)
 Read meteorological grid information and construct the domain-decomposed grid with halo regions. More...
 
void read_met_pbl (const ctl_t *ctl, met_t *met)
 Computes the planetary boundary layer (PBL) pressure based on meteorological data. More...
 
void read_met_periodic (met_t *met)
 Applies periodic boundary conditions to meteorological data along longitudinal axis. More...
 
void read_met_polar_winds (met_t *met)
 Applies a fix for polar winds in meteorological data. More...
 
void read_met_pv (met_t *met)
 Calculates potential vorticity (PV) from meteorological data. More...
 
void read_met_ozone (met_t *met)
 Calculates the total column ozone from meteorological ozone data. More...
 
void read_met_sample (const ctl_t *ctl, met_t *met)
 Downsamples meteorological data based on specified parameters. More...
 
void read_met_tropo (const ctl_t *ctl, const clim_t *clim, met_t *met)
 Calculates the tropopause and related meteorological variables based on various methods and stores the results in the meteorological data structure. More...
 
void read_obs (const char *filename, const ctl_t *ctl, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
 Reads observation data from a file and stores it in arrays. More...
 
void read_obs_asc (const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
 Reads observation data from an ASCII file. More...
 
void read_obs_nc (const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
 Reads observation data from a NetCDF file. More...
 
double scan_ctl (const char *filename, int argc, char *argv[], const char *varname, const int arridx, const char *defvalue, char *value)
 Scans a control file or command-line arguments for a specified variable. More...
 
double sedi (const double p, const double T, const double rp, const double rhop)
 Calculates the sedimentation velocity of a particle in air. More...
 
void spline (const double *x, const double *y, const int n, const double *x2, double *y2, const int n2, const int method)
 Performs spline interpolation or linear interpolation. More...
 
float stddev (const float *data, const int n)
 Calculates the standard deviation of a set of data. More...
 
void time2jsec (const int year, const int mon, const int day, const int hour, const int min, const int sec, const double remain, double *jsec)
 Converts time components to seconds since January 1, 2000, 12:00:00 UTC. More...
 
void timer (const char *name, const char *group, const int output)
 Measures and reports elapsed time for named and grouped timers. More...
 
double time_from_filename (const char *filename, const int offset, const int with_seconds)
 Extracts and converts a timestamp from a filename to Julian seconds. More...
 
double tropo_weight (const ctl_t *ctl, const clim_t *clim, const atm_t *atm, const int ip)
 Computes a weighting factor based on tropopause pressure. More...
 
void write_atm_asc (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes air parcel data to an ASCII file or gnuplot. More...
 
void write_atm_bin (const char *filename, const ctl_t *ctl, const atm_t *atm)
 Writes air parcel data to a binary file. More...
 
void write_atm_clams (const char *filename, const ctl_t *ctl, const atm_t *atm)
 Writes air parcel data to a NetCDF file in the CLaMS format. More...
 
void write_atm_clams_traj (const char *dirname, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes CLaMS trajectory data to a NetCDF file. More...
 
void write_atm_nc (const char *filename, const ctl_t *ctl, const atm_t *atm)
 Writes air parcel data to a NetCDF file. More...
 
void write_csi (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes Critical Success Index (CSI) data to a file. More...
 
void write_ens (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes ensemble data to a file. More...
 
void write_depo (const char *filename, const ctl_t *ctl, const depo_t *depo, const double t)
 Convert cumulative ground inventories to Bq m^-2 and write them. More...
 
void write_depo_asc (const char *filename, const ctl_t *ctl, const double *data, const double t, const double *lon, const double *lat, const double *area)
 Write radioactive deposition densities as a gnuplot-compatible table. More...
 
void write_depo_nc (const char *filename, const ctl_t *ctl, const double *data, const double t, const double *lon, const double *lat, const double *area)
 Write radioactive deposition densities as a CF-style netCDF file. More...
 
void write_grid (const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
 Writes grid data to a file in ASCII or netCDF format. More...
 
void write_grid_asc (const char *filename, const ctl_t *ctl, const double *cd, double *mean[NQ], double *sigma[NQ], const double *vmr_impl, const double t, const double *z, const double *lon, const double *lat, const double *area, const double dz, const int *np)
 Writes grid data to an ASCII file. More...
 
void write_grid_nc (const char *filename, const ctl_t *ctl, const double *cd, double *mean[NQ], double *sigma[NQ], const double *vmr_impl, const double t, const double *z, const double *lon, const double *lat, const double *area, const double dz, const int *np)
 Writes grid data to a NetCDF file. More...
 
void write_met_bin (const char *filename, const ctl_t *ctl, met_t *met)
 Writes meteorological data in binary format to a specified file. More...
 
void write_met_bin_2d (FILE *out, met_t *met, float var[EX][EY], const char *varname)
 Writes a 2-dimensional meteorological variable to a binary file. More...
 
void write_met_bin_3d (FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int metvar, FILE *level_log)
 Writes a 3-dimensional meteorological variable to a binary file. More...
 
void write_met_nc (const char *filename, const ctl_t *ctl, met_t *met)
 Writes meteorological data to a NetCDF file. More...
 
void write_met_nc_2d (const int ncid, const char *varname, met_t *met, float var[EX][EY], const float scl)
 Writes a 2D meteorological variable to a NetCDF file. More...
 
void write_met_nc_3d (const int ncid, const char *varname, met_t *met, float var[EX][EY][EP], const float scl)
 Writes a 3D meteorological variable to a NetCDF file. More...
 
void write_prof (const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
 Writes profile data to a specified file. More...
 
void write_sample (const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
 Writes sample data to a specified file. More...
 
void write_station (const char *filename, const ctl_t *ctl, atm_t *atm, const double t)
 Writes station data to a specified file. More...
 
void write_vtk (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes VTK (Visualization Toolkit) data to a specified file. More...
 

Detailed Description

MPTRAC library definitions.

Definition in file mptrac.c.

Function Documentation

◆ cart2geo()

void cart2geo ( const double *  x,
double *  z,
double *  lon,
double *  lat 
)

State variables of cuRAND random number generator.

Converts Cartesian coordinates to geographic coordinates.

Definition at line 74 of file mptrac.c.

78 {
79
80 const double radius = sqrt(DOTP(x, x));
81
82 *lat = RAD2DEG(asin(x[2] / radius));
83 *lon = RAD2DEG(atan2(x[1], x[0]));
84 *z = radius - RE;
85}
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:314
#define DOTP(a, b)
Calculate the dot product of two vectors.
Definition: mptrac.h:1035
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1875

◆ clim_oh()

double clim_oh ( const ctl_t ctl,
const clim_t clim,
const double  t,
const double  lon,
const double  lat,
const double  p 
)

Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal correction based on solar zenith angle.

This function retrieves OH data from a given climatology and applies a diurnal correction if the correction factor (oh_chem_beta) is greater than zero. The diurnal correction accounts for the variation in OH concentration due to changes in the solar zenith angle.

Parameters
ctlPointer to the control structure containing configuration parameters.
climPointer to the climatology structure containing OH data.
tTime at which the OH concentration is to be calculated.
lonLongitude at which the OH concentration is to be calculated.
latLatitude at which the OH concentration is to be calculated.
pPressure level at which the OH concentration is to be calculated.
Returns
The OH concentration at the specified time, location, and pressure, possibly adjusted by a diurnal correction.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 89 of file mptrac.c.

95 {
96
97 /* Set SZA threshold... */
98 const double sza_thresh = DEG2RAD(85.), csza_thresh = cos(sza_thresh);
99
100 /* Set reference coordinates... */
101 const double lat_ref =
102 ctl->met_coord_type == 0 ? lat : ctl->met_utm_ref_lat;
103 double lon_ref = ctl->met_coord_type == 0 ? lon : ctl->met_utm_ref_lon;
104 while (lon_ref < -180.0)
105 lon_ref += 360.0;
106 while (lon_ref >= 180.0)
107 lon_ref -= 360.0;
108
109 /* Get OH data from climatology... */
110 const double oh = clim_zm(&clim->oh, t, lat_ref, p);
111
112 /* Check beta... */
113 if (ctl->oh_chem_beta <= 0)
114 return oh;
115
116 /* Apply diurnal correction... */
117 const double csza = cos_sza(t, lon_ref, lat_ref);
118 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
119 return oh * exp(-ctl->oh_chem_beta / denom);
120}
double cos_sza(const double sec, const double lon, const double lat)
Calculates the cosine of the solar zenith angle.
Definition: mptrac.c:1857
double clim_zm(const clim_zm_t *zm, const double t, const double lat, const double p)
Interpolates monthly mean zonal mean climatological variables.
Definition: mptrac.c:414
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:856
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3811
double met_utm_ref_lon
Reference longitude [deg] for UTM grid.
Definition: mptrac.h:2855
double met_utm_ref_lat
Reference latitude [deg] for UTM grid.
Definition: mptrac.h:2852
double oh_chem_beta
Beta parameter for diurnal variability of OH.
Definition: mptrac.h:3236
int met_coord_type
Type of coordinates for meteo data (-1=detect, 0=lat/lon [deg], 1=UTM [m]).
Definition: mptrac.h:2849
Here is the call graph for this function:

◆ clim_oh_diurnal_correction()

void clim_oh_diurnal_correction ( const ctl_t ctl,
clim_t clim 
)

Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data.

This function iterates over the climatology data points for OH concentration and integrates the day/night correction factor over longitude. The correction factor is based on the solar zenith angle, and it adjusts the OH data to account for diurnal variations. The corrected OH data is scaled accordingly.

Parameters
ctlPointer to the control structure containing configuration parameters, including the correction factor (oh_chem_beta).
climPointer to the climatology structure containing OH data that will be corrected.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 124 of file mptrac.c.

126 {
127
128 /* Set SZA threshold... */
129 const double sza_thresh = DEG2RAD(85.), csza_thresh = cos(sza_thresh);
130
131 /* Loop over climatology data points... */
132 for (int it = 0; it < clim->oh.ntime; it++)
133 for (int iz = 0; iz < clim->oh.np; iz++)
134 for (int iy = 0; iy < clim->oh.nlat; iy++) {
135
136 /* Init... */
137 int n = 0;
138 double sum = 0;
139
140 /* Integrate day/night correction factor over longitude... */
141 for (double lon = -180; lon < 180; lon += 1.0) {
142 const double csza =
143 cos_sza(clim->oh.time[it], lon, clim->oh.lat[iy]);
144 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
145 sum += exp(-ctl->oh_chem_beta / denom);
146 n++;
147 }
148
149 /* Apply scaling factor to OH data... */
150 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
151 }
152}
double time[CT]
Time [s].
Definition: mptrac.h:3767
int np
Number of pressure levels.
Definition: mptrac.h:3764
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3776
int ntime
Number of timesteps.
Definition: mptrac.h:3758
int nlat
Number of latitudes.
Definition: mptrac.h:3761
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3770
Here is the call graph for this function:

◆ clim_photo()

double clim_photo ( const double  rate[CP][CSZA][CO3],
const clim_photo_t photo,
const double  p,
const double  sza,
const double  o3c 
)

Calculates the photolysis rate for a given set of atmospheric conditions.

This function computes the photolysis rate based on provided climatology data and input parameters such as pressure, solar zenith angle (SZA), and ozone column. It ensures that the input parameters are within the valid range of the climatology data and interpolates the photolysis rate accordingly.

Parameters
rate3D array containing the photolysis rates for different combinations of pressure, SZA, and ozone column.
photoPointer to the climatology data structure containing arrays of valid pressure levels, SZAs, and ozone columns.
pPressure at which the photolysis rate is to be calculated.
szaSolar zenith angle at which the photolysis rate is to be calculated.
o3cOzone column at which the photolysis rate is to be calculated.
Returns
The interpolated photolysis rate for the specified conditions. If the calculated rate is negative, it returns 0.0.

This function performs the following steps:

  1. Checks and adjusts the input parameters (pressure, SZA, and ozone column) to ensure they are within the valid range.
  2. Determines the appropriate indices in the climatology data for interpolation.
  3. Performs trilinear interpolation to calculate the photolysis rate based on the input parameters.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 156 of file mptrac.c.

161 {
162
163 /* Check pressure range... */
164 double p_help = p;
165 if (p < photo->p[photo->np - 1])
166 p_help = photo->p[photo->np - 1];
167 else if (p > photo->p[0])
168 p_help = photo->p[0];
169
170 /* Check sza range... */
171 double sza_help = sza;
172 if (sza < photo->sza[0])
173 sza_help = photo->sza[0];
174 else if (sza > photo->sza[photo->nsza - 1])
175 sza_help = photo->sza[photo->nsza - 1];
176
177 /* Check ozone column range... */
178 double o3c_help = o3c;
179 if (o3c < photo->o3c[0])
180 o3c_help = photo->o3c[0];
181 else if (o3c > photo->o3c[photo->no3c - 1])
182 o3c_help = photo->o3c[photo->no3c - 1];
183
184 /* Get indices... */
185 const int ip = locate_irr(photo->p, photo->np, p_help);
186 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
187 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
188
189 /* Interpolate photolysis rate... */
190 const double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
191 photo->p[ip + 1], rate[ip + 1][isza][io3c],
192 p_help);
193 const double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
194 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1],
195 p_help);
196 const double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
197 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c],
198 p_help);
199 const double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
200 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
201 p_help);
202 const double aux0 =
203 LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
204 const double aux1 =
205 LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
206 const double aux =
207 LIN(photo->sza[isza], aux0, photo->sza[isza + 1], aux1, sza_help);
208 return MAX(aux, 0.0);
209}
int locate_reg(const double *xx, const int n, const double x)
Locate the index of the interval containing a given value in a regular grid.
Definition: mptrac.c:3559
int locate_irr(const double *xx, const int n, const double x)
Locate the index of the interval containing a given value in a sorted array.
Definition: mptrac.c:3495
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1350
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1377
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3685
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3694
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3691
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3697
int np
Number of pressure levels.
Definition: mptrac.h:3682
int no3c
Number of total ozone columns.
Definition: mptrac.h:3688
Here is the call graph for this function:

◆ clim_tropo()

double clim_tropo ( const clim_t clim,
const double  t,
const double  lat 
)

Calculates the tropopause pressure based on climatological data.

This function computes the tropopause pressure using climatological data for different times and latitudes. It interpolates the tropopause pressure based on the input time and latitude parameters.

Parameters
climPointer to the climatology structure containing tropopause pressure data.
tTime for which the tropopause pressure is to be calculated, in seconds since the beginning of the year.
latLatitude at which the tropopause pressure is to be calculated.
Returns
The interpolated tropopause pressure for the specified time and latitude.

This function performs the following steps:

  1. Calculates the number of seconds since the beginning of the year.
  2. Determines the appropriate indices in the climatology data for interpolation based on time and latitude.
  3. Interpolates the tropopause pressure using linear interpolation based on latitude and time.
Author
Lars Hoffmann

Definition at line 213 of file mptrac.c.

216 {
217
218 /* Get seconds since begin of year... */
219 double sec = FMOD(t, 365.25 * 86400.);
220 while (sec < 0)
221 sec += 365.25 * 86400.;
222
223 /* Get indices... */
224 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
225 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
226
227 /* Interpolate tropopause pressure... */
228 const double p0 = LIN(clim->tropo_lat[ilat],
229 clim->tropo[isec][ilat],
230 clim->tropo_lat[ilat + 1],
231 clim->tropo[isec][ilat + 1], lat);
232 const double p1 = LIN(clim->tropo_lat[ilat],
233 clim->tropo[isec + 1][ilat],
234 clim->tropo_lat[ilat + 1],
235 clim->tropo[isec + 1][ilat + 1], lat);
236 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
237}
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:1120
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3790
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3799
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3793
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3802
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3796
Here is the call graph for this function:

◆ clim_tropo_init()

void clim_tropo_init ( clim_t clim)

Initializes the tropopause data in the climatology structure.

This function initializes the tropopause data in the climatology structure. It sets the time steps, latitudes, and tropopause pressure values based on predefined arrays.

Parameters
climPointer to the climatology structure to be initialized.

This function performs the following steps:

  1. Sets the number of time steps and initializes the time array.
  2. Sets the number of latitudes and initializes the latitude array.
  3. Initializes the tropopause pressure values based on predefined arrays.
  4. Computes the range of tropopause pressure values.
  5. Logs information about the initialization process.
Author
Lars Hoffmann

Definition at line 241 of file mptrac.c.

242 {
243
244 /* Write info... */
245 LOG(1, "Initialize tropopause data...");
246
247 /* Set time [s]... */
248 clim->tropo_ntime = 12;
249 double tropo_time[12] = {
250 1209600.00, 3888000.00, 6393600.00,
251 9072000.00, 11664000.00, 14342400.00,
252 16934400.00, 19612800.00, 22291200.00,
253 24883200.00, 27561600.00, 30153600.00
254 };
255 memcpy(clim->tropo_time, tropo_time, sizeof(clim->tropo_time));
256
257 /* Set latitudes [deg]... */
258 clim->tropo_nlat = 73;
259 const double tropo_lat[73] = {
260 -90, -87.5, -85, -82.5, -80, -77.5, -75, -72.5, -70, -67.5,
261 -65, -62.5, -60, -57.5, -55, -52.5, -50, -47.5, -45, -42.5,
262 -40, -37.5, -35, -32.5, -30, -27.5, -25, -22.5, -20, -17.5,
263 -15, -12.5, -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10, 12.5,
264 15, 17.5, 20, 22.5, 25, 27.5, 30, 32.5, 35, 37.5, 40, 42.5,
265 45, 47.5, 50, 52.5, 55, 57.5, 60, 62.5, 65, 67.5, 70, 72.5,
266 75, 77.5, 80, 82.5, 85, 87.5, 90
267 };
268 memcpy(clim->tropo_lat, tropo_lat, sizeof(clim->tropo_lat));
269
270 /* Set tropopause pressure [hPa] (NCEP/NCAR Reanalysis 1)... */
271 const double tropo[12][73] = {
272 {324.1, 325.6, 325, 324.3, 322.5, 319.7, 314, 307.2, 301.8, 299.6,
273 297.1, 292.2, 285.6, 276.1, 264, 248.9, 231.9, 213.5, 194.4,
274 175.3, 157, 140.4, 126.7, 116.3, 109.5, 105.4, 103, 101.4, 100.4,
275 99.69, 99.19, 98.84, 98.56, 98.39, 98.39, 98.42, 98.44, 98.54,
276 98.68, 98.81, 98.89, 98.96, 99.12, 99.65, 101.4, 105.4, 113.5, 128,
277 152.1, 184.7, 214, 234.1, 247.3, 255.8, 262.6, 267.7, 271.7, 275,
278 277.2, 279, 280.1, 280.4, 280.6, 280.1, 279.3, 278.3, 276.8, 275.8,
279 275.3, 275.6, 275.4, 274.1, 273.5},
280 {337.3, 338.7, 337.8, 336.4, 333, 328.8, 321.1, 312.6, 306.6, 303.7,
281 300.2, 293.8, 285.4, 273.8, 259.6, 242.7, 224.4, 205.2, 186, 167.5,
282 150.3, 135, 122.8, 113.9, 108.2, 104.7, 102.5, 101.1, 100.2, 99.42,
283 98.88, 98.52, 98.25, 98.09, 98.07, 98.1, 98.12, 98.2, 98.25, 98.27,
284 98.26, 98.27, 98.36, 98.79, 100.2, 104.2, 113.7, 131.2, 159.5, 193,
285 220.4, 238.1, 250.2, 258.1, 264.7, 269.7, 273.7, 277.3, 280.2, 282.8,
286 284.9, 286.5, 288.1, 288.8, 289, 288.5, 287.2, 286.3, 286.1, 287.2,
287 287.5, 286.2, 285.8},
288 {335, 336, 335.7, 335.1, 332.3, 328.1, 320.6, 311.8, 305.1, 301.9,
289 297.6, 290, 280.4, 268.3, 254.6, 239.6, 223.9, 207.9, 192.2, 176.9,
290 161.7, 146.4, 132.2, 120.6, 112.3, 107.2, 104.3, 102.4, 101.3,
291 100.4, 99.86, 99.47, 99.16, 98.97, 98.94, 98.97, 99, 99.09, 99.2,
292 99.31, 99.35, 99.41, 99.51, 99.86, 101.1, 104.9, 114.3, 131, 156.8,
293 186.3, 209.3, 224.6, 236.8, 246.3, 254.9, 262.3, 268.8, 274.8,
294 279.9, 284.6, 288.6, 291.6, 294.9, 297.5, 299.8, 301.8, 303.1,
295 304.3, 304.9, 306, 306.6, 306.2, 306},
296 {306.2, 306.7, 305.7, 307.1, 307.3, 306.4, 301.8, 296.2, 292.4,
297 290.3, 287.1, 280.9, 273.4, 264.3, 254.1, 242.8, 231, 219, 207.2,
298 195.5, 183.3, 169.7, 154.7, 138.7, 124.1, 113.6, 107.8, 104.7,
299 102.8, 101.7, 100.9, 100.4, 100, 99.79, 99.7, 99.66, 99.68, 99.79,
300 99.94, 100.2, 100.5, 100.9, 101.4, 102.1, 103.4, 107, 115.2, 129.1,
301 148.7, 171, 190.8, 205.6, 218.4, 229.4, 239.6, 248.6, 256.5,
302 263.7, 270.3, 276.6, 282.6, 288.1, 294.5, 300.4, 306.3, 311.4,
303 315.1, 318.3, 320.3, 322.2, 322.8, 321.5, 321.1},
304 {266.5, 264.9, 260.8, 261, 262, 263, 261.3, 259.7, 259.2, 259.8,
305 260.1, 258.6, 256.7, 253.6, 249.5, 243.9, 237.4, 230, 222.1, 213.9,
306 205, 194.4, 180.4, 161.8, 140.7, 122.9, 112.1, 106.7, 104.1, 102.7,
307 101.8, 101.4, 101.1, 101, 101, 101, 101.1, 101.2, 101.5, 101.9,
308 102.4, 103, 103.8, 104.9, 106.8, 110.1, 115.6, 124, 135.2, 148.9,
309 165.2, 181.3, 198, 211.8, 223.5, 233.8, 242.9, 251.5, 259, 266.2,
310 273.1, 279.2, 286.2, 292.8, 299.6, 306, 311.1, 315.5, 318.8, 322.6,
311 325.3, 325.8, 325.8},
312 {220.1, 218.1, 210.8, 207.2, 207.6, 210.5, 211.4, 213.5, 217.3,
313 222.4, 227.9, 232.8, 237.4, 240.8, 242.8, 243, 241.5, 238.6, 234.2,
314 228.5, 221, 210.7, 195.1, 172.9, 147.8, 127.6, 115.6, 109.9, 107.1,
315 105.7, 105, 104.8, 104.8, 104.9, 105, 105.1, 105.3, 105.5, 105.8,
316 106.4, 107, 107.6, 108.1, 108.8, 110, 111.8, 114.2, 117.4, 121.6,
317 127.9, 137.3, 151.2, 169.5, 189, 205.8, 218.9, 229.1, 237.8, 245,
318 251.5, 257.1, 262.3, 268.2, 274, 280.4, 286.7, 292.4, 297.9, 302.9,
319 308.5, 312.2, 313.1, 313.3},
320 {187.4, 184.5, 173.3, 166.1, 165.4, 167.8, 169.6, 173.6, 179.6,
321 187.9, 198.9, 210, 220.5, 229.2, 235.7, 239.9, 241.8, 241.6, 239.6,
322 235.8, 229.4, 218.6, 200.9, 175.9, 149.4, 129.4, 118.3, 113.1,
323 110.8, 109.7, 109.3, 109.4, 109.7, 110, 110.2, 110.4, 110.5, 110.7,
324 111, 111.4, 111.8, 112.1, 112.3, 112.7, 113.2, 113.9, 115, 116.4,
325 117.9, 120.4, 124.1, 130.9, 142.2, 159.6, 179.6, 198.5, 212.9,
326 224.2, 232.7, 239.1, 243.8, 247.7, 252.4, 257.3, 263.2, 269.5,
327 275.4, 281.1, 286.3, 292, 296.3, 298.2, 298.8},
328 {166, 166.4, 155.7, 148.3, 147.1, 149, 152.1, 157, 163.6, 172.4,
329 185.3, 199.2, 212.6, 224, 233.2, 239.6, 243.3, 244.6, 243.6, 240.3,
330 233.9, 222.6, 203.7, 177, 149.5, 129.7, 119, 114, 111.7, 110.7,
331 110.3, 110.3, 110.6, 110.9, 111.1, 111.3, 111.5, 111.6, 111.9,
332 112.2, 112.5, 112.6, 112.8, 113, 113.4, 114, 115.1, 116.5, 118.3,
333 120.9, 124.4, 130.2, 139.4, 154.6, 173.8, 193.1, 208.1, 220.4,
334 230.1, 238.2, 244.7, 249.5, 254.5, 259.3, 264.5, 269.4, 273.7,
335 278.2, 282.6, 287.4, 290.9, 292.5, 293},
336 {171.9, 172.8, 166.2, 162.3, 161.4, 162.5, 165.2, 169.6, 175.3,
337 183.1, 193.8, 205.9, 218.3, 229.6, 238.5, 244.3, 246.9, 246.7,
338 243.8, 238.4, 230.2, 217.9, 199.6, 174.9, 148.9, 129.8, 119.5,
339 114.8, 112.3, 110.9, 110.3, 110.1, 110.2, 110.3, 110.4, 110.5,
340 110.6, 110.8, 111, 111.4, 111.8, 112, 112.2, 112.4, 112.9, 113.6,
341 114.7, 116.3, 118.4, 121.9, 127.1, 136.1, 149.8, 168.4, 186.9,
342 203.3, 217, 229.1, 238.7, 247, 254, 259.3, 264.3, 268.3, 272.5,
343 276.6, 280.4, 284.4, 288.4, 293.3, 297.2, 298.7, 299.1},
344 {191.6, 192.2, 189, 188.1, 190.2, 193.7, 197.8, 202.9, 208.5,
345 215.6, 224.2, 233.1, 241.2, 247.3, 250.8, 251.3, 248.9, 244.2,
346 237.3, 228.4, 217.2, 202.9, 184.5, 162.5, 140.7, 124.8, 116.2,
347 111.8, 109.4, 107.9, 107, 106.7, 106.6, 106.6, 106.7, 106.7,
348 106.8, 107, 107.4, 108, 108.7, 109.3, 109.8, 110.4, 111.2,
349 112.4, 114.2, 116.9, 121.1, 127.9, 139.3, 155.2, 173.6, 190.7,
350 206.1, 220.1, 232.3, 243, 251.8, 259.2, 265.7, 270.6, 275.3,
351 279.3, 283.3, 286.9, 289.7, 292.8, 296.1, 300.5, 303.9, 304.8,
352 305.1},
353 {241.5, 239.6, 236.8, 237.4, 239.4, 242.3, 244.2, 246.4, 249.2,
354 253.6, 258.6, 262.7, 264.8, 264.2, 260.6, 254.1, 245.5, 235.3,
355 223.9, 211.7, 198.3, 183.1, 165.6, 147.1, 130.5, 118.7, 111.9,
356 108.1, 105.8, 104.3, 103.4, 102.8, 102.5, 102.4, 102.5, 102.5,
357 102.5, 102.7, 103.1, 103.8, 104.6, 105.4, 106.1, 107, 108.2,
358 109.9, 112.8, 117.5, 126, 140.4, 161, 181.9, 201.2, 216.8, 230.4,
359 241.8, 251.4, 259.9, 266.9, 272.8, 277.4, 280.4, 282.9, 284.6,
360 286.1, 287.4, 288.3, 289.5, 290.9, 294.2, 296.9, 297.5, 297.6},
361 {301.2, 300.3, 296.6, 295.4, 295, 294.3, 291.2, 287.4, 284.9, 284.7,
362 284.1, 281.5, 277.1, 270.4, 261.7, 250.6, 237.6, 223.1, 207.9, 192,
363 175.8, 158.8, 142.1, 127.6, 116.8, 109.9, 106, 103.6, 102.1, 101.1,
364 100.4, 99.96, 99.6, 99.37, 99.32, 99.32, 99.31, 99.46, 99.77, 100.2,
365 100.7, 101.3, 101.8, 102.7, 104.1, 106.8, 111.9, 121, 136.7, 160,
366 186.9, 209.9, 228.1, 241.2, 251.5, 259.5, 265.7, 270.9, 274.8, 278,
367 280.3, 281.8, 283, 283.3, 283.7, 283.8, 283, 282.2, 281.2, 281.4,
368 281.7, 281.1, 281.2}
369 };
370 memcpy(clim->tropo, tropo, sizeof(clim->tropo));
371
372 /* Get range... */
373 double tropomin = 1e99, tropomax = -1e99;
374 for (int it = 0; it < clim->tropo_ntime; it++)
375 for (int iy = 0; iy < clim->tropo_nlat; iy++) {
376 tropomin = MIN(tropomin, clim->tropo[it][iy]);
377 tropomax = MAX(tropomax, clim->tropo[it][iy]);
378 }
379
380 /* Write info... */
381 LOG(2, "Number of time steps: %d", clim->tropo_ntime);
382 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
383 clim->tropo_time[0], clim->tropo_time[1],
384 clim->tropo_time[clim->tropo_ntime - 1]);
385 LOG(2, "Number of latitudes: %d", clim->tropo_nlat);
386 LOG(2, "Latitudes: %g, %g ... %g deg",
387 clim->tropo_lat[0], clim->tropo_lat[1],
388 clim->tropo_lat[clim->tropo_nlat - 1]);
389 LOG(2, "Tropopause altitude range: %g ... %g hPa", Z(tropomax),
390 Z(tropomin));
391 LOG(2, "Tropopause pressure range: %g ... %g hPa", tropomin, tropomax);
392}
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:1478
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:2242
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:2335

◆ clim_ts()

double clim_ts ( const clim_ts_t ts,
const double  t 
)

Interpolates a time series of climatological variables.

This function interpolates a time series of climatological variables based on the input time and the provided data points.

Parameters
tsPointer to the time series structure containing data points.
tTime at which to interpolate the climatological variable (in seconds).
Returns
Interpolated value of the climatological variable at the given time.

This function performs linear interpolation between the closest data points to the input time t. If t is outside the range of the provided time series, the value at the nearest boundary is returned.

Author
Lars Hoffmann

Definition at line 396 of file mptrac.c.

398 {
399
400 /* Interpolate... */
401 if (t <= ts->time[0])
402 return ts->vmr[0];
403 else if (t >= ts->time[ts->ntime - 1])
404 return ts->vmr[ts->ntime - 1];
405 else {
406 const int idx = locate_irr(ts->time, ts->ntime, t);
407 return LIN(ts->time[idx], ts->vmr[idx],
408 ts->time[idx + 1], ts->vmr[idx + 1], t);
409 }
410}
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3744
double time[CTS]
Time [s].
Definition: mptrac.h:3741
int ntime
Number of timesteps.
Definition: mptrac.h:3738
Here is the call graph for this function:

◆ clim_zm()

double clim_zm ( const clim_zm_t zm,
const double  t,
const double  lat,
const double  p 
)

Interpolates monthly mean zonal mean climatological variables.

This function interpolates climatological variables based on pressure, latitude, and time. The climatological data is provided in the form of monthly mean zonal mean values.

Parameters
zmPointer to the climatological zonal mean structure containing data points.
tTime at which to interpolate the climatological variable (in seconds since the beginning of the year).
latLatitude at which to interpolate the climatological variable (in degrees).
pPressure at which to interpolate the climatological variable (in hPa).
Returns
Interpolated value of the climatological variable at the given pressure, latitude, and time.

This function performs trilinear interpolation between the nearest data points to the input time t, latitude lat, and pressure or altitude p. If the input values are outside the range of the provided data, the function extrapolates by using the nearest boundary values.

Author
Lars Hoffmann

Definition at line 414 of file mptrac.c.

418 {
419
420 /* Get seconds since begin of year... */
421 double sec = FMOD(t, 365.25 * 86400.);
422 while (sec < 0)
423 sec += 365.25 * 86400.;
424
425 /* Check pressure range... */
426 double p_help = p;
427 if (p < zm->p[zm->np - 1])
428 p_help = zm->p[zm->np - 1];
429 else if (p > zm->p[0])
430 p_help = zm->p[0];
431
432 /* Check latitude range... */
433 double lat_help = lat;
434 if (lat < zm->lat[0])
435 lat_help = zm->lat[0];
436 else if (lat > zm->lat[zm->nlat - 1])
437 lat_help = zm->lat[zm->nlat - 1];
438
439 /* Get indices... */
440 const int isec = locate_irr(zm->time, zm->ntime, sec);
441 const int ilat = locate_reg(zm->lat, zm->nlat, lat_help);
442 const int ip = locate_irr(zm->p, zm->np, p_help);
443
444 /* Interpolate climatology data... */
445 const double aux00 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat],
446 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat],
447 p_help);
448 const double aux01 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat + 1],
449 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat + 1],
450 p_help);
451 const double aux10 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat],
452 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat],
453 p_help);
454 const double aux11 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat + 1],
455 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat + 1],
456 p_help);
457 const double aux0 =
458 LIN(zm->lat[ilat], aux00, zm->lat[ilat + 1], aux01, lat_help);
459 const double aux1 =
460 LIN(zm->lat[ilat], aux10, zm->lat[ilat + 1], aux11, lat_help);
461 const double aux = LIN(zm->time[isec], aux0, zm->time[isec + 1], aux1, sec);
462 return MAX(aux, 0.0);
463}
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3773
Here is the call graph for this function:

◆ compress_log_level()

void compress_log_level ( FILE *  out,
const char *  codec,
const char *  varname,
const size_t  lev,
const double  plev,
const double  ratio,
const double  bpv,
const double  t_comp,
const double  t_decomp,
const size_t  n,
const size_t  nbytes,
const float *  org,
const float *  cmp 
)

Write one row of per-level compression diagnostics.

This helper computes the error statistics for one level (from org and cmp) and writes one ASCII table row to out. If rho is NAN, the correlation coefficient is derived from org and cmp using GSL.

Parameters
[in,out]outOutput stream.
[in]codecCompression codec name.
[in]varnameVariable name.
[in]levLevel index.
[in]plevPressure level in hPa.
[in]ratioCompression ratio.
[in]bpvBits per value.
[in]t_compCompression time in seconds.
[in]t_decompDecompression time in seconds.
[in]nNumber of data values in the level slice.
[in]nbytesByte count used for throughput reporting.
[in]orgOriginal level data.
[in]cmpReconstructed level data.
Author
Lars Hoffmann

Definition at line 666 of file mptrac.c.

679 {
680
681 static FILE *last_out = NULL;
682 static char last_var[LEN] = "";
683
684 /* Calculate error statistics... */
685 double mean_err = 0.0, stddev_err = 0.0;
686 double nrmse = NAN, mean_orig = 0.0, orig_range = 0.0, rho = NAN;
687
688 double sum_err = 0.0, sumsq_err = 0.0;
689 double sum_orig = 0.0, sum_cmp = 0.0;
690 double sumsq_orig = 0.0, sumsq_cmp = 0.0, sum_org_cmp = 0.0;
691
692 double min_orig = 0.0, max_orig = 0.0;
693 double min_err = 0.0, max_err = 0.0;
694
695 /* Accumulate error, signal and cross-product sums in one pass... */
696 for (size_t i = 0; i < n; i++) {
697 const double o = (double) org[i];
698 const double c = (double) cmp[i];
699 const double e = c - o;
700
701 sum_err += e;
702 sumsq_err += e * e;
703 sum_orig += o;
704 sum_cmp += c;
705
706 sumsq_orig += o * o;
707 sumsq_cmp += c * c;
708 sum_org_cmp += o * c;
709
710 if (e < min_err || i == 0)
711 min_err = e;
712 if (e > max_err || i == 0)
713 max_err = e;
714
715 if (o < min_orig || i == 0)
716 min_orig = o;
717 if (o > max_orig || i == 0)
718 max_orig = o;
719 }
720
721 /* Derive the basic error and signal summary statistics... */
722 mean_err = sum_err / (double) n;
723 mean_orig = sum_orig / (double) n;
724 orig_range = max_orig - min_orig;
725
726 /* Convert the accumulated error sums into a standard deviation... */
727 const double var_err =
728 (sumsq_err - (sum_err * sum_err) / (double) n) / (double) n;
729 stddev_err = sqrt(var_err > 0.0 ? var_err : 0.0);
730
731 /* Normalize RMSE by the original data range if available... */
732 nrmse = (orig_range > 0.0)
733 ? sqrt(sumsq_err / (double) n) / orig_range : NAN;
734
735 /* Compute the Pearson correlation from the accumulated moments... */
736 const double nn = (double) n;
737 const double cov = sum_org_cmp - sum_orig * sum_cmp / nn;
738 const double var_orig = sumsq_orig - sum_orig * sum_orig / nn;
739 const double var_cmp = sumsq_cmp - sum_cmp * sum_cmp / nn;
740 const double denom = sqrt(var_orig * var_cmp);
741 rho = denom > 0.0 ? cov / denom : NAN;
742
743 /* Reset the variable separator state when the target file changes... */
744 if (out != last_out) {
745 last_out = out;
746 last_var[0] = '\0';
747 }
748
749 /* Separate diagnostic blocks when switching to a new variable... */
750 if (last_var[0] != '\0' && strcmp(last_var, varname) != 0)
751 fprintf(out, "\n");
752 snprintf(last_var, LEN, "%s", varname);
753
754 /* Logging... */
755 fprintf(out,
756 "%s %s %lu %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n",
757 codec, varname, (unsigned long) lev, plev, ratio, bpv, rho,
758 mean_err, stddev_err, min_err, max_err, mean_orig, orig_range,
759 nrmse, t_comp, COMPRESS_SPEED(nbytes, t_comp), t_decomp,
760 COMPRESS_SPEED(nbytes, t_decomp));
761}
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:558
#define COMPRESS_SPEED(nbytes, dt)
Calculate compression throughput in MiB/s.
Definition: mptrac.h:770

◆ compress_log_levels_3d()

void compress_log_levels_3d ( FILE *  out,
const char *  codec,
const char *  varname,
const met_t met,
const float *  org_all,
const float *  cmp_all,
const size_t  nxy,
const size_t  nz,
const double  ratio,
const double  bpv,
const double  t_comp,
const double  t_decomp,
const size_t  nbytes 
)

Write per-level compression diagnostics for a full 3-D field.

This helper extracts each vertical level from the original and reconstructed 3-D fields and forwards the diagnostics to compress_log_level().

Parameters
[in,out]outOutput stream, or NULL to disable logging.
[in]codecCompression codec name.
[in]varnameVariable name.
[in]metMeteorological meta-data with pressure levels.
[in]org_allOriginal 3-D field in horizontal-major order.
[in]cmp_allReconstructed 3-D field in horizontal-major order.
[in]nxyNumber of horizontal points per level.
[in]nzNumber of vertical levels.
[in]ratioCompression ratio.
[in]bpvBits per value.
[in]t_compCompression time in seconds.
[in]t_decompDecompression time in seconds.
[in]nbytesByte count used for throughput reporting.
Author
Lars Hoffmann

Definition at line 765 of file mptrac.c.

778 {
779
780 if (!out)
781 return;
782
783 /* Allocate temporary buffers for one level... */
784 float *tmp_org, *tmp_cmp;
785 ALLOC(tmp_org, float,
786 nxy);
787 ALLOC(tmp_cmp, float,
788 nxy);
789
790 for (size_t lev = 0; lev < nz; lev++) {
791
792 /* Extract current level... */
793#pragma omp parallel for default(shared)
794 for (size_t ixy = 0; ixy < nxy; ixy++) {
795 tmp_org[ixy] = org_all[ixy * nz + lev];
796 tmp_cmp[ixy] = cmp_all[ixy * nz + lev];
797 }
798
799 /* Write diagnostics for the extracted level... */
800 compress_log_level(out, codec, varname, lev, met->p[lev], ratio, bpv,
801 t_comp, t_decomp, nxy, nbytes, tmp_org, tmp_cmp);
802 }
803
804 /* Free... */
805 free(tmp_org);
806 free(tmp_cmp);
807}
void compress_log_level(FILE *out, const char *codec, const char *varname, const size_t lev, const double plev, const double ratio, const double bpv, const double t_comp, const double t_decomp, const size_t n, const size_t nbytes, const float *org, const float *cmp)
Write one row of per-level compression diagnostics.
Definition: mptrac.c:666
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:666
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3873
Here is the call graph for this function:

◆ compress_scale_to_unit()

void compress_scale_to_unit ( float *  array,
const size_t  nxy,
const size_t  nz,
double *  off,
double *  scl 
)

Scales each vertical level of a 3-D field independently to the interval [0,1].

The routine computes per-level offsets and scales from the minimum and maximum values of each vertical slice and transforms the field in place. Constant or nearly constant levels are mapped to zero and can be reconstructed exactly with the stored offsets.

Parameters
[in,out]arrayField values stored in horizontal-major order.
[in]nxyNumber of horizontal points per level.
[in]nzNumber of vertical levels.
[out]offPer-level offsets (minimum values).
[out]sclPer-level scales (ranges).
Author
Lars Hoffmann

Definition at line 811 of file mptrac.c.

816 {
817
818 /* Initialize per-level minima and maxima from the first sample... */
819 for (size_t iz = 0; iz < nz; iz++) {
820 off[iz] = array[iz];
821 scl[iz] = array[iz];
822 }
823
824 /* Scan the remaining samples to get per-level minima and maxima... */
825 for (size_t ixy = 1; ixy < nxy; ixy++)
826 for (size_t iz = 0; iz < nz; iz++) {
827 const double value = array[ixy * nz + iz];
828 if (value < off[iz])
829 off[iz] = value;
830 if (value > scl[iz])
831 scl[iz] = value;
832 }
833
834 /* Convert maxima into ranges and suppress numerically flat levels... */
835 for (size_t iz = 0; iz < nz; iz++) {
836 const double range = scl[iz] - off[iz];
837 const double ref = fmax(1.0, fmax(fabs(off[iz]), fabs(scl[iz])));
838 scl[iz] = !(range > 1e-12 * ref) ? 0.0 : range;
839 }
840
841 /* Scale each level independently to the unit interval... */
842#pragma omp parallel for default(shared)
843 for (size_t ixy = 0; ixy < nxy; ixy++)
844 for (size_t iz = 0; iz < nz; iz++)
845 if (scl[iz] > 0.0)
846 array[ixy * nz + iz] =
847 (float) ((array[ixy * nz + iz] - off[iz]) / scl[iz]);
848 else
849 array[ixy * nz + iz] = 0.0f;
850}

◆ compress_unscale_from_unit()

void compress_unscale_from_unit ( float *  array,
const size_t  nxy,
const size_t  nz,
const double *  off,
const double *  scl 
)

Restores a levelwise [0,1]-scaled 3-D field to physical units.

This routine applies the inverse transformation of compress_scale_to_unit() using the supplied per-level offsets and scales. Constant levels are restored directly from their offsets.

Parameters
[in,out]arrayField values stored in horizontal-major order.
[in]nxyNumber of horizontal points per level.
[in]nzNumber of vertical levels.
[in]offPer-level offsets (minimum values).
[in]sclPer-level scales (ranges).
Author
Lars Hoffmann

Definition at line 854 of file mptrac.c.

859 {
860
861 /* Restore each level from unit space back to its original range... */
862#pragma omp parallel for default(shared)
863 for (size_t ixy = 0; ixy < nxy; ixy++)
864 for (size_t iz = 0; iz < nz; iz++)
865 if (scl[iz] > 0.0)
866 array[ixy * nz + iz] =
867 (float) (array[ixy * nz + iz] * scl[iz] + off[iz]);
868 else
869 array[ixy * nz + iz] = (float) off[iz];
870}

◆ compress_read_lossy_scale()

int compress_read_lossy_scale ( FILE *  in,
const size_t  nz,
double **  off,
double **  scl 
)

Read optional lossyscaling metadata for a 3-D field.

This helper reads the stored MET_LOSSY_SCALE flag and, if enabled, allocates and fills the per-level offset and scale arrays used by compress_unscale_from_unit(). The caller owns the returned arrays and must free them.

Parameters
[in,out]inInput stream.
[in]nzNumber of vertical levels.
[out]offReturned per-level offsets, or NULL if disabled.
[out]sclReturned per-level scales, or NULL if disabled.
Returns
Stored lossyscaling flag (0 or 1).
Author
Lars Hoffmann

Definition at line 874 of file mptrac.c.

878 {
879
880 int enabled;
881 *off = NULL;
882 *scl = NULL;
883
884 /* Read input... */
885 FREAD(&enabled, int,
886 1,
887 in);
888 if (enabled < 0 || enabled > 1)
889 ERRMSG("Invalid stored MET_LOSSY_SCALE flag!");
890
891 if (enabled > 0) {
892 ALLOC(*off, double,
893 nz);
894 ALLOC(*scl, double,
895 nz);
896 FREAD(*off, double,
897 nz,
898 in);
899 FREAD(*scl, double,
900 nz,
901 in);
902 }
903
904 return enabled;
905}
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2405
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:1138

◆ compress_write_lossy_scale()

void compress_write_lossy_scale ( FILE *  out,
const int  enabled,
float *  array,
const size_t  nxy,
const size_t  nz,
double **  off,
double **  scl 
)

Write optional lossyscaling metadata for a 3-D field.

This helper writes the MET_LOSSY_SCALE flag and, if enabled, allocates the per-level offset and scale arrays, scales the field in place to [0,1], and writes the resulting metadata to out. The caller owns the returned arrays and must free them.

Parameters
[in,out]outOutput stream.
[in]enabledLossyscaling flag (0 or 1).
[in,out]arrayField values stored in horizontal-major order.
[in]nxyNumber of horizontal points per level.
[in]nzNumber of vertical levels.
[out]offReturned per-level offsets, or NULL if disabled.
[out]sclReturned per-level scales, or NULL if disabled.
Author
Lars Hoffmann

Definition at line 909 of file mptrac.c.

916 {
917
918 *off = NULL;
919 *scl = NULL;
920
921 /* Write output... */
922 FWRITE(&enabled, int,
923 1,
924 out);
925 if (enabled <= 0)
926 return;
927
928 /* Derive per-level scaling data... */
929 ALLOC(*off, double,
930 nz);
931 ALLOC(*scl, double,
932 nz);
933
934 compress_scale_to_unit(array, nxy, nz, *off, *scl);
935
936 FWRITE(*off, double,
937 nz,
938 out);
939 FWRITE(*scl, double,
940 nz,
941 out);
942}
void compress_scale_to_unit(float *array, const size_t nxy, const size_t nz, double *off, double *scl)
Scales each vertical level of a 3-D field independently to the interval [0,1].
Definition: mptrac.c:811
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:1158
Here is the call graph for this function:

◆ compress_metvar_index()

int compress_metvar_index ( const char *  varname)

Maps a meteorological variable name to its internal MPTRAC variable index.

The returned index can be used to access variable-specific control arrays such as MET_LOSSY_SCALE, MET_ZFP_PREC, and MET_SZ3_PREC.

Parameters
varnameMeteorological variable name as stored in the meteorological file.
Returns
Internal MPTRAC meteorological variable index.
Author
Lars Hoffmann

Definition at line 969 of file mptrac.c.

970 {
971
972 static const char *const names[] = {
973 "Z", "T", "U", "V", "W", "PV", "H2O", "O3",
974 "LWC", "RWC", "IWC", "SWC", "CC"
975 };
976
977 for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); i++)
978 if (strcasecmp(varname, names[i]) == 0)
979 return (int) i;
980
981 ERRMSG("Unknown meteorological variable name!");
982}

◆ compress_pck()

void compress_pck ( const ctl_t ctl,
const met_t met,
const char *  varname,
float *  array,
const int  decompress,
FILE *  level_log,
FILE *  inout 
)

Compresses or decompresses a 3‑D float array using the PCK format.

The routine works on the regular longitude/latitude grid described by the supplied met structure (nx, ny, np and pressure levels). In compress mode the data are scaled to unsigned short values; in decompress mode the values are reconstructed.

Parameters
[in]ctlControl structure with compression parameters.
[in]metMeteorological meta‑data providing grid dimensions and pressure levels.
[in]varnameVariable name for logging and error‑bound selection.
[in,out]arrayFloat array to compress or decompress.
[in]decompressNon‑zero to decompress; zero to compress.
[in,out]level_logOptional per‑level diagnostics stream, or NULL.
[in,out]inoutFile stream for reading/writing the PCK payload.
Author
Lars Hoffmann

Definition at line 986 of file mptrac.c.

993 {
994
995 const size_t nxy = (size_t) met->nx * (size_t) met->ny;
996 const size_t nz = (size_t) met->np;
997 const size_t n = nxy * nz;
998 const size_t nbytes = n * sizeof(float);
999 const size_t pck_bytes = n * sizeof(uint16_t);
1000
1001 double vmin[EP], vmax[EP], off[EP], scl[EP];
1002 uint16_t *sarray;
1003
1004 /* PCK+ZSTD payload = scale + offset + packed 16-bit samples... */
1005 const size_t payload_len = 2 * nz * sizeof(double) + pck_bytes;
1006 size_t stored_len = payload_len;
1007 const char *codec_info = ctl->met_pck_zstd ? "PCK+ZSTD" : "PCK";
1008
1009 /* Allocate packed sample buffer... */
1010 ALLOC(sarray, uint16_t, n);
1011
1012 /* Read compressed stream and decompress array... */
1013 if (decompress) {
1014 double t_zstd = 0.0;
1015
1016 /* Read packed data... */
1017 if (ctl->met_pck_zstd) {
1018#ifdef ZSTD
1019 uint64_t magic, pck_zstd_magic = UINT64_C(0x50434b5a53544431);
1020 unsigned char *compr = NULL, *payload = NULL;
1021
1022 /* Read input... */
1023 FREAD(&magic, uint64_t, 1, inout);
1024 if (magic != pck_zstd_magic)
1025 ERRMSG("PCK+ZSTD magic mismatch! Check MET_PCK_ZSTD and file type.");
1026
1027 /* Read and decompress the outer ZSTD payload... */
1028 FREAD(&stored_len, size_t,
1029 1,
1030 inout);
1031 ALLOC(compr, unsigned char,
1032 stored_len);
1033 FREAD(compr, unsigned char,
1034 stored_len,
1035 inout);
1036 ALLOC(payload, unsigned char,
1037 payload_len);
1038 const double t0_decomp = omp_get_wtime();
1039 const size_t out_len =
1040 ZSTD_decompress(payload, payload_len, compr, stored_len);
1041 t_zstd = omp_get_wtime() - t0_decomp;
1042 if (ZSTD_isError(out_len) || out_len != payload_len)
1043 ERRMSG("PCK ZSTD decompression failed or size mismatch!");
1044
1045 /* Split payload into scale, offset and packed samples... */
1046 memcpy(scl, payload, nz * sizeof(double));
1047 memcpy(off, payload + nz * sizeof(double), nz * sizeof(double));
1048 memcpy(sarray, payload + 2 * nz * sizeof(double), pck_bytes);
1049
1050 /* Free... */
1051 free(payload);
1052 free(compr);
1053#else
1054 ERRMSG("MPTRAC was compiled without ZSTD compression!");
1055#endif
1056 } else {
1057 /* Read input... */
1058 FREAD(&scl, double,
1059 nz,
1060 inout);
1061 FREAD(&off, double,
1062 nz,
1063 inout);
1064 FREAD(sarray, uint16_t, n, inout);
1065 }
1066
1067 /* Measure the scalar unpacking step separately from optional ZSTD... */
1068 const double t0 = omp_get_wtime();
1069
1070 /* Convert packed 16-bit samples back to floating-point values... */
1071#pragma omp parallel for default(shared)
1072 for (size_t ixy = 0; ixy < nxy; ixy++)
1073 for (size_t iz = 0; iz < nz; iz++)
1074 array[ixy * nz + iz]
1075 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1076
1077 /* Add optional ZSTD time to the scalar unpacking time... */
1078 const double t_decomp = t_zstd + omp_get_wtime() - t0;
1079
1080 /* Logging... */
1081 LOG(2, "Read 3-D variable: %s"
1082 " (%s, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1083 varname, codec_info, COMPRESS_RATIO(nbytes, stored_len),
1084 COMPRESS_BPV(n, stored_len), t_decomp, COMPRESS_SPEED(nbytes,
1085 t_decomp));
1086 }
1087
1088 /* Compress array and output compressed stream... */
1089 else {
1090 float *tmp_org, *tmp_pck;
1091 double t_comp_sum = 0, t_decomp_sum = 0, t_zstd = 0, t_zstd_decomp = 0;
1092 double t_comp_level[EP], t_decomp_level[EP];
1093
1094 /* Allocate temporary buffers for one level... */
1095 ALLOC(tmp_org, float,
1096 nxy);
1097 ALLOC(tmp_pck, float,
1098 nxy);
1099
1100 /* Derive per-level minima and maxima for the 16-bit quantization... */
1101 for (size_t iz = 0; iz < nz; iz++) {
1102 vmin[iz] = array[iz];
1103 vmax[iz] = array[iz];
1104 }
1105 for (size_t ixy = 1; ixy < nxy; ixy++)
1106 for (size_t iz = 0; iz < nz; iz++) {
1107 if (array[ixy * nz + iz] < vmin[iz])
1108 vmin[iz] = array[ixy * nz + iz];
1109 if (array[ixy * nz + iz] > vmax[iz])
1110 vmax[iz] = array[ixy * nz + iz];
1111 }
1112
1113 /* Derive per-level offset and scaling factor... */
1114 for (size_t iz = 0; iz < nz; iz++) {
1115 scl[iz] = (vmax[iz] - vmin[iz]) / 65533.;
1116 off[iz] = vmin[iz];
1117 }
1118
1119 /* Quantize each level and time encode/decode diagnostics on the fly... */
1120 for (size_t iz = 0; iz < nz; iz++) {
1121 const double t0 = omp_get_wtime();
1122
1123#pragma omp parallel for default(shared)
1124 for (size_t ixy = 0; ixy < nxy; ixy++)
1125 if (scl[iz] != 0)
1126 sarray[ixy * nz + iz] =
1127 (uint16_t) ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
1128 else
1129 sarray[ixy * nz + iz] = 0;
1130
1131 t_comp_level[iz] = omp_get_wtime() - t0;
1132 t_comp_sum += t_comp_level[iz];
1133
1134 const double t1 = omp_get_wtime();
1135
1136#pragma omp parallel for default(shared)
1137 for (size_t ixy = 0; ixy < nxy; ixy++) {
1138 tmp_org[ixy] = array[ixy * nz + iz];
1139 tmp_pck[ixy] = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1140 }
1141
1142 t_decomp_level[iz] = omp_get_wtime() - t1;
1143 t_decomp_sum += t_decomp_level[iz];
1144 }
1145
1146 /* Write packed data, optionally wrapped in ZSTD... */
1147 if (ctl->met_pck_zstd) {
1148#ifdef ZSTD
1149 uint64_t pck_zstd_magic = UINT64_C(0x50434b5a53544431);
1150 unsigned char *payload = NULL, *payload_chk = NULL;
1151 void *stored_data = NULL;
1152
1153 /* Pack plain PCK data into one ZSTD payload... */
1154 ALLOC(payload, unsigned char,
1155 payload_len);
1156 memcpy(payload, scl, nz * sizeof(double));
1157 memcpy(payload + nz * sizeof(double), off, nz * sizeof(double));
1158 memcpy(payload + 2 * nz * sizeof(double), sarray, pck_bytes);
1159 const size_t dst_cap = ZSTD_compressBound(payload_len);
1160 ALLOC(stored_data, char,
1161 dst_cap);
1162 ZSTD_CCtx *cctx = compress_zstd_create_cctx(ctl->met_zstd_level,
1163 ctl->met_zstd_nworkers);
1164 const double t0_comp = omp_get_wtime();
1165 stored_len =
1166 ZSTD_compress2(cctx, stored_data, dst_cap, payload, payload_len);
1167 t_zstd = omp_get_wtime() - t0_comp;
1168 ZSTD_freeCCtx(cctx);
1169 if (ZSTD_isError(stored_len))
1170 ERRMSG("PCK ZSTD compression failed!");
1171
1172 /* Decompress once for validation and timing... */
1173 ALLOC(payload_chk, unsigned char,
1174 payload_len);
1175 const double t0_decomp2 = omp_get_wtime();
1176 const size_t out_len2 =
1177 ZSTD_decompress(payload_chk, payload_len, stored_data, stored_len);
1178 t_zstd_decomp = omp_get_wtime() - t0_decomp2;
1179 if (ZSTD_isError(out_len2) || out_len2 != payload_len)
1180 ERRMSG("PCK ZSTD decompression failed or size mismatch!");
1181
1182 /* Free... */
1183 free(payload_chk);
1184 free(payload);
1185
1186 /* Write output... */
1187 FWRITE(&pck_zstd_magic, uint64_t, 1, inout);
1188 FWRITE(&stored_len, size_t,
1189 1,
1190 inout);
1191 FWRITE(stored_data, unsigned char,
1192 stored_len,
1193 inout);
1194
1195 /* Free... */
1196 free(stored_data);
1197#else
1198 ERRMSG("MPTRAC was compiled without ZSTD compression!");
1199#endif
1200 } else {
1201
1202 /* Write output... */
1203 FWRITE(&scl, double,
1204 nz,
1205 inout);
1206 FWRITE(&off, double,
1207 nz,
1208 inout);
1209 FWRITE(sarray, uint16_t, n, inout);
1210 }
1211
1212 /* Combine PCK and optional ZSTD timing and size metrics... */
1213 const double ratio_out = COMPRESS_RATIO(nbytes, stored_len);
1214 const double bpv_out = COMPRESS_BPV(n, stored_len);
1215 const double t_comp = t_comp_sum + t_zstd;
1216 const double t_decomp = t_decomp_sum + t_zstd_decomp;
1217
1218 /* Logging... */
1219 LOG(2, "Write 3-D variable: %s"
1220 " (%s, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1221 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1222 varname, codec_info, ratio_out, bpv_out, t_comp,
1223 COMPRESS_SPEED(nbytes, t_comp), t_decomp,
1224 COMPRESS_SPEED(nbytes, t_decomp));
1225
1226 /* Distribute optional ZSTD cost across levels for diagnostics... */
1227 if (level_log) {
1228 const double t_zstd_level = t_zstd / (double) nz;
1229 const double t_zstd_decomp_level = t_zstd_decomp / (double) nz;
1230 const char *codec = ctl->met_pck_zstd ? "PCKZSTD" : "PCK";
1231 for (size_t iz = 0; iz < nz; iz++) {
1232#pragma omp parallel for default(shared)
1233
1234 /* Rebuild one decoded level for diagnostics... */
1235 for (size_t ixy = 0; ixy < nxy; ixy++) {
1236 tmp_org[ixy] = array[ixy * nz + iz];
1237 tmp_pck[ixy] = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1238 }
1239
1240 /* Logging... */
1241 compress_log_level(level_log, codec, varname, iz, met->p[iz],
1242 ratio_out, bpv_out,
1243 t_comp_level[iz] + t_zstd_level,
1244 t_decomp_level[iz] + t_zstd_decomp_level,
1245 nxy, nxy * sizeof(float), tmp_org, tmp_pck);
1246 }
1247 }
1248
1249 /* Free... */
1250 free(tmp_org);
1251 free(tmp_pck);
1252 }
1253
1254 /* Free... */
1255 free(sarray);
1256}
#define COMPRESS_BPV(n, stored_size)
Calculate bits per value from stored size and element count.
Definition: mptrac.h:794
#define COMPRESS_RATIO(raw_size, stored_size)
Calculate the compression ratio from raw and stored byte counts.
Definition: mptrac.h:782
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:543
int met_zstd_nworkers
ZSTD number of worker threads (0=single-threaded, default=4).
Definition: mptrac.h:2884
int met_zstd_level
ZSTD compression level (from -5 to 22, default=-3).
Definition: mptrac.h:2881
int met_pck_zstd
Apply an additional ZSTD compression step to PCK payloads (0=off, 1=on).
Definition: mptrac.h:2890
int nx
Number of longitudes.
Definition: mptrac.h:3855
int ny
Number of latitudes.
Definition: mptrac.h:3858
int np
Number of pressure levels.
Definition: mptrac.h:3861
Here is the call graph for this function:

◆ cos_sza()

double cos_sza ( const double  sec,
const double  lon,
const double  lat 
)

Calculates the cosine of the solar zenith angle.

This function computes the cosine of the solar zenith angle (SZA), which describes the angle between the local zenith (straight up) and the line connecting the observer to the center of the Sun. The cosine of the SZA is often used directly in radiative transfer and photochemical calculations to avoid unnecessary use of trigonometric inverse functions.

Parameters
secSeconds elapsed since 2000-01-01T12:00Z.
lonObserver's longitude in degrees.
latObserver's latitude in degrees.
Returns
The cosine of the solar zenith angle (dimensionless, range [-1, 1]).

The cosine of the solar zenith angle is computed based on the observer's position (longitude and latitude) and the specified time in seconds elapsed since 2000-01-01T12:00Z.

Note
The input longitude and latitude must be specified in degrees.
See also
acos() — can be used to convert the returned value to the solar zenith angle in radians if needed.
Author
Lars Hoffmann

Definition at line 1857 of file mptrac.c.

1860 {
1861
1862 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
1863 const double D = sec / 86400 - 0.5;
1864
1865 /* Geocentric apparent ecliptic longitude [rad]... */
1866 const double g = DEG2RAD(357.529 + 0.98560028 * D);
1867 const double q = 280.459 + 0.98564736 * D;
1868 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
1869
1870 /* Mean obliquity of the ecliptic [rad]... */
1871 const double e = DEG2RAD(23.439 - 0.00000036 * D);
1872
1873 /* Declination [rad]... */
1874 const double sindec = sin(e) * sin(L);
1875
1876 /* Right ascension [rad]... */
1877 const double ra = atan2(cos(e) * sin(L), cos(L));
1878
1879 /* Greenwich Mean Sidereal Time [h]... */
1880 const double GMST = 18.697374558 + 24.06570982441908 * D;
1881
1882 /* Local Sidereal Time [h]... */
1883 const double LST = GMST + lon / 15;
1884
1885 /* Hour angle [rad]... */
1886 const double h = LST / 12 * M_PI - ra;
1887
1888 /* Convert latitude... */
1889 const double lat_help = DEG2RAD(lat);
1890
1891 /* Return cosine of solar zenith angle... */
1892 return sin(lat_help) * sindec + cos(lat_help) * sqrt(1 -
1893 SQR(sindec)) * cos(h);
1894}
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:2036

◆ day2doy()

void day2doy ( const int  year,
const int  mon,
const int  day,
int *  doy 
)

Get day of year from date.

Converts a given date to the day of the year (DOY).

This function computes the day of the year (DOY) for a given date specified by the year, month, and day. It takes into account whether the given year is a leap year or not.

Parameters
yearThe year of the date.
monThe month of the date (1-12).
dayThe day of the month (1-31).
doyPointer to an integer where the computed day of the year will be stored.

The function uses two arrays, d0 and d0l, which contain the cumulative number of days at the start of each month for non-leap years and leap years respectively. It checks if the year is a leap year and calculates the day of the year accordingly.

Note
The function assumes that the input date is valid.
Author
Lars Hoffmann

Definition at line 1898 of file mptrac.c.

1902 {
1903
1904 const int
1905 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1906 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1907
1908 /* Get day of year... */
1909 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
1910 *doy = d0l[mon - 1] + day - 1;
1911 else
1912 *doy = d0[mon - 1] + day - 1;
1913}

◆ doy2day()

void doy2day ( const int  year,
const int  doy,
int *  mon,
int *  day 
)

Converts a given day of the year (DOY) to a date (month and day).

This function computes the month and day for a given day of the year (DOY) and year. It accounts for whether the given year is a leap year or not.

Parameters
yearThe year corresponding to the DOY.
doyThe day of the year (1-365 or 1-366).
monPointer to an integer where the computed month will be stored.
dayPointer to an integer where the computed day of the month will be stored.

The function uses two arrays, d0 and d0l, which contain the cumulative number of days at the start of each month for non-leap years and leap years respectively. It checks if the year is a leap year and calculates the month and day of the month accordingly.

Note
The function assumes that the input DOY is valid for the given year.
Author
Lars Hoffmann

Definition at line 2532 of file mptrac.c.

2536 {
2537
2538 const int
2539 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
2540 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
2541
2542 int i;
2543
2544 /* Get month and day... */
2545 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
2546 for (i = 11; i > 0; i--)
2547 if (d0l[i] <= doy)
2548 break;
2549 *mon = i + 1;
2550 *day = doy - d0l[i] + 1;
2551 } else {
2552 for (i = 11; i > 0; i--)
2553 if (d0[i] <= doy)
2554 break;
2555 *mon = i + 1;
2556 *day = doy - d0[i] + 1;
2557 }
2558}

◆ fft_help()

void fft_help ( double *  fcReal,
double *  fcImag,
const int  n 
)

Computes the Fast Fourier Transform (FFT) of a complex sequence.

This function calculates the FFT of a complex sequence represented by separate arrays for the real and imaginary parts. The input arrays fcReal and fcImag are modified in place to contain the transformed data.

Parameters
fcRealPointer to an array of doubles representing the real part of the input sequence. The array should have at least n elements.
fcImagPointer to an array of doubles representing the imaginary part of the input sequence. The array should have at least n elements.
nThe number of complex data points in the input sequence. This value should not exceed PMAX.
Precondition
fcReal and fcImag must point to arrays of at least n elements.
n must be less than or equal to PMAX.
Postcondition
The arrays fcReal and fcImag will contain the real and imaginary parts of the FFT result, respectively.
Note
This function uses the GNU Scientific Library (GSL) for computing the FFT. Ensure that GSL is properly installed and linked in your project.
Warning
If n exceeds PMAX, the function will trigger an error message and terminate.
Author
Lars Hoffmann

Definition at line 2562 of file mptrac.c.

2565 {
2566
2567 double data[2 * EX];
2568
2569 /* Check size... */
2570 if (n > EX)
2571 ERRMSG("Too many data points!");
2572
2573 /* Allocate... */
2574 gsl_fft_complex_wavetable *wavetable =
2575 gsl_fft_complex_wavetable_alloc((size_t) n);
2576 gsl_fft_complex_workspace *workspace =
2577 gsl_fft_complex_workspace_alloc((size_t) n);
2578
2579 /* Set data (real, complex)... */
2580 for (int i = 0; i < n; i++) {
2581 data[2 * i] = fcReal[i];
2582 data[2 * i + 1] = fcImag[i];
2583 }
2584
2585 /* Calculate FFT... */
2586 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
2587
2588 /* Copy data... */
2589 for (int i = 0; i < n; i++) {
2590 fcReal[i] = data[2 * i];
2591 fcImag[i] = data[2 * i + 1];
2592 }
2593
2594 /* Free... */
2595 gsl_fft_complex_wavetable_free(wavetable);
2596 gsl_fft_complex_workspace_free(workspace);
2597}
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:548

◆ geo2cart()

void geo2cart ( const double  z,
const double  lon,
const double  lat,
double *  x 
)

Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates.

This function converts geographic coordinates specified by longitude, latitude, and altitude into Cartesian coordinates. The Earth is approximated as a sphere with radius defined by the constant RE.

Parameters
zThe altitude above the Earth's surface in kilometers.
lonThe longitude in degrees.
latThe latitude in degrees.
xPointer to an array of three doubles where the computed Cartesian coordinates (x, y, z) will be stored.

The function computes the Cartesian coordinates using the given altitude, longitude, and latitude. It assumes the Earth is a perfect sphere and uses the following formulas:

  • \( x = (\textrm{radius}) \cos(\textrm{lat in radians}) \cos(\textrm{lon in radians}) \)
  • \( y = (\textrm{radius}) \cos(\textrm{lat in radians}) \sin(\textrm{lon in radians}) \)
  • \( z = (\textrm{radius}) \sin(\textrm{lat in radians}) \)
Note
The constant RE is defined as the Earth's radius in kilometers.
Longitude and latitude should be in degrees.
See also
https://en.wikipedia.org/wiki/Geographic_coordinate_conversion
Author
Lars Hoffmann

Definition at line 2601 of file mptrac.c.

2605 {
2606
2607 const double radius = z + RE;
2608 const double latrad = DEG2RAD(lat);
2609 const double lonrad = DEG2RAD(lon);
2610 const double coslat = cos(latrad);
2611
2612 x[0] = radius * coslat * cos(lonrad);
2613 x[1] = radius * coslat * sin(lonrad);
2614 x[2] = radius * sin(latrad);
2615}

◆ get_met_filename()

void get_met_filename ( const ctl_t ctl,
const double  t,
const int  direct,
const char *  metbase,
const double  dt_met,
char *  filename 
)

Generates a formatted filename for meteorological data files based on the input parameters.

This function determines a rounded time interval, decodes the time components (year, month, day, hour, minute, second), and constructs a filename string for meteorological data files in various formats. The filename is adjusted based on the input control settings.

Parameters
[in]ctlPointer to the control structure containing configuration settings.
[in]tThe time value in seconds since a reference epoch.
[in]directDirection to round the time value. Use -1 for rounding down and 1 for rounding up.
[in]metbaseBase string for the filename, representing the dataset.
[in]dt_metTime interval for rounding in seconds.
[out]filenameOutput buffer to store the generated filename.
Note
The function modifies the provided filename buffer to include placeholders (e.g., YYYY, MM, DD, HH) replaced with the corresponding time values. The format of the filename depends on the values in the control structure (e.g., ctl->met_type).
Warning
Ensure that the filename buffer has sufficient size to accommodate the resulting string.
Author
Lars Hoffmann

Definition at line 2619 of file mptrac.c.

2625 {
2626
2627 char repl[LEN];
2628
2629 double t6, r;
2630
2631 int year, mon, day, hour, min, sec;
2632
2633 /* Round time to fixed intervals... */
2634 if (direct == -1)
2635 t6 = floor(t / dt_met) * dt_met;
2636 else
2637 t6 = ceil(t / dt_met) * dt_met;
2638
2639 /* Decode time... */
2640 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
2641
2642 /* Set filename of MPTRAC meteo files... */
2643 if (ctl->met_clams == 0) {
2644 if (ctl->met_type == 0)
2645 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
2646 else if (ctl->met_type == 1)
2647 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
2648 else if (ctl->met_type == 2)
2649 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
2650 else if (ctl->met_type == 3)
2651 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
2652 else if (ctl->met_type == 4)
2653 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
2654 else if (ctl->met_type == 5)
2655 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
2656 else if (ctl->met_type == 7)
2657 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
2658 else if (ctl->met_type == 8)
2659 sprintf(filename, "%s_YYYY_MM_DD_HH.lz4", metbase);
2660 sprintf(repl, "%d", year);
2661 get_met_replace(filename, "YYYY", repl);
2662 sprintf(repl, "%02d", mon);
2663 get_met_replace(filename, "MM", repl);
2664 sprintf(repl, "%02d", day);
2665 get_met_replace(filename, "DD", repl);
2666 sprintf(repl, "%02d", hour);
2667 get_met_replace(filename, "HH", repl);
2668 }
2669
2670 /* Set filename of CLaMS meteo files... */
2671 else {
2672 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
2673 sprintf(repl, "%d", year);
2674 get_met_replace(filename, "YYYY", repl);
2675 sprintf(repl, "%02d", year % 100);
2676 get_met_replace(filename, "YY", repl);
2677 sprintf(repl, "%02d", mon);
2678 get_met_replace(filename, "MM", repl);
2679 sprintf(repl, "%02d", day);
2680 get_met_replace(filename, "DD", repl);
2681 sprintf(repl, "%02d", hour);
2682 get_met_replace(filename, "HH", repl);
2683 }
2684}
void jsec2time(const double jsec, int *year, int *mon, int *day, int *hour, int *min, int *sec, double *remain)
Converts Julian seconds to calendar date and time components.
Definition: mptrac.c:3265
void get_met_replace(char *orig, const char *search, const char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:2688
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2869
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=ZFP, 4=ZSTD, 5=cms, 6=grib,...
Definition: mptrac.h:2866
Here is the call graph for this function:

◆ get_met_replace()

void get_met_replace ( char *  orig,
const char *  search,
const char *  repl 
)

Replaces occurrences of a substring in a string with another substring.

This function replaces occurrences of the substring search in the string orig with the substring repl. The replacement is performed in-place.

Parameters
origThe original string where replacements are to be made.
searchThe substring to be replaced.
replThe substring to replace occurrences of search.

The function iterates over the original string orig and replaces each occurrence of the substring search with the substring repl. It performs the replacement operation up to three times to ensure multiple occurrences are replaced.

Note
We use this function to replace the strings YYYY, MM, and DD by year, month, and day in filenames.
Ensure that orig, search, and repl are properly initialized and have sufficient memory allocated before calling this function.
Author
Lars Hoffmann

Definition at line 2688 of file mptrac.c.

2691 {
2692
2693 char buffer[LEN];
2694
2695 /* Iterate... */
2696 for (int i = 0; i < 3; i++) {
2697
2698 /* Replace sub-string... */
2699 char *ch;
2700 if (!(ch = strstr(orig, search)))
2701 return;
2702 strncpy(buffer, orig, (size_t) (ch - orig));
2703 buffer[ch - orig] = 0;
2704 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
2705 orig[0] = 0;
2706 strcpy(orig, buffer);
2707 }
2708}

◆ get_tropo()

void get_tropo ( const int  met_tropo,
ctl_t ctl,
const clim_t clim,
met_t met,
const double *  lons,
const int  nx,
const double *  lats,
const int  ny,
double *  pt,
double *  zt,
double *  tt,
double *  qt,
double *  o3t,
double *  ps,
double *  zs 
)

Calculate tropopause data.

This function reads and interpolates various meteorological parameters such as tropopause pressure, temperature, and ozone concentration at specified latitudes and longitudes. The interpolated data is stored in the provided arrays.

Parameters
met_tropoAn integer specifying the type of meteorological data to use.
ctlPointer to a ctl_t structure that controls the meteorological data processing.
climPointer to a clim_t structure containing climatological data.
metPointer to a met_t structure containing meteorological data.
lonsArray of longitudes at which to interpolate data. The array should have nx elements.
nxNumber of longitude points.
latsArray of latitudes at which to interpolate data. The array should have ny elements.
nyNumber of latitude points.
ptPointer to an array where the interpolated pressure values will be stored. The array should have nx * ny elements.
ztPointer to an array where the interpolated height values will be stored. The array should have nx * ny elements.
ttPointer to an array where the interpolated temperature values will be stored. The array should have nx * ny elements.
qtPointer to an array where the interpolated specific humidity values will be stored. The array should have nx * ny elements.
o3tPointer to an array where the interpolated ozone concentration values will be stored. The array should have nx * ny elements.
psPointer to an array where the interpolated surface pressure values will be stored. The array should have nx * ny elements.
zsPointer to an array where the interpolated surface height values will be stored. The array should have nx * ny elements.
Precondition
lons must have at least nx elements.
lats must have at least ny elements.
pt, zt, tt, qt, o3t, ps, and zs must have at least nx * ny elements.
Postcondition
The arrays pt, zt, tt, qt, o3t, ps, and zs will contain the interpolated meteorological data.
Note
The function utilizes OpenMP for parallel processing of the interpolation tasks.
The function uses the auxiliary functions read_met_tropo, intpol_met_space_2d, and intpol_met_space_3d for reading and interpolating the tropopause data.
Author
Lars Hoffmann

Definition at line 2712 of file mptrac.c.

2727 {
2728
2730
2731 ctl->met_tropo = met_tropo;
2732 read_met_tropo(ctl, clim, met);
2733#pragma omp parallel for default(shared) private(ci,cw)
2734 for (int ix = 0; ix < nx; ix++)
2735 for (int iy = 0; iy < ny; iy++) {
2736 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2737 &pt[iy * nx + ix], ci, cw, 1);
2738 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2739 &ps[iy * nx + ix], ci, cw, 0);
2740 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2741 &zs[iy * nx + ix], ci, cw, 0);
2742 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2743 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2744 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2745 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2746 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2747 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2748 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2749 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2750 }
2751}
void intpol_met_space_2d(const met_t *met, float array[EX][EY], const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological variables in 2D space.
Definition: mptrac.c:3048
void read_met_tropo(const ctl_t *ctl, const clim_t *clim, met_t *met)
Calculates the tropopause and related meteorological variables based on various methods and stores th...
Definition: mptrac.c:12187
void intpol_met_space_3d(const met_t *met, float array[EX][EY][EP], const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological variables in 3D space.
Definition: mptrac.c:2985
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:1173
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2990
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3978
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3888
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3894
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3981
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3963
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3921
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3960
Here is the call graph for this function:

◆ intpol_check_lon_lat()

void intpol_check_lon_lat ( const double *  lons,
const int  nlon,
const double *  lats,
const int  nlat,
const double  lon,
const double  lat,
double *  lon2,
double *  lat2 
)

Adjusts longitude and latitude to ensure they fall within valid bounds.

This function checks and modifies the given longitude and latitude values to fit within the specified longitude and latitude arrays. The longitude is wrapped within a 360-degree range, and the latitude is clamped within the valid range defined by the latitude array.

Parameters
[in]lonsPointer to an array of valid longitude values.
[in]nlonNumber of elements in the longitude array.
[in]latsPointer to an array of valid latitude values.
[in]nlatNumber of elements in the latitude array.
[in]lonInput longitude to be checked and adjusted.
[in]latInput latitude to be checked and adjusted.
[out]lon2Pointer to the adjusted longitude.
[out]lat2Pointer to the adjusted latitude.
Author
Lars Hoffmann

Definition at line 2755 of file mptrac.c.

2763 {
2764
2765 /* Check longitude... */
2766 *lon2 = FMOD(lon, 360.);
2767 if (*lon2 < lons[0])
2768 *lon2 += 360;
2769 else if (*lon2 > lons[nlon - 1])
2770 *lon2 -= 360;
2771
2772 /* Check latitude... */
2773 *lat2 = lat;
2774 if (lats[0] < lats[nlat - 1])
2775 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
2776 else
2777 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
2778}

◆ intpol_check_cartesian()

void intpol_check_cartesian ( const double *  lons,
const int  nlon,
const double *  lats,
const int  nlat,
const double  lon,
const double  lat,
double *  lon2,
double *  lat2 
)

Clamps UTM coordinates to the valid bounds.

This function constrains the given UTM easting and northing values so they remain within the limits defined by the provided x and y coordinate arrays.

Parameters
[in]lonsPointer to an array of valid x/easting values.
[in]nlonNumber of elements in the x/easting array.
[in]latsPointer to an array of valid y/northing values.
[in]nlatNumber of elements in the y/northing array.
[in]lonInput x/easting coordinate to be checked and adjusted.
[in]latInput y/northing coordinate to be checked and adjusted.
[out]lon2Pointer to the adjusted x/easting coordinate.
[out]lat2Pointer to the adjusted y/northing coordinate.
Author
Robin Brase

Definition at line 2782 of file mptrac.c.

2790 {
2791
2792 *lon2 = lon;
2793 if (lons[0] < lons[nlon - 1])
2794 *lon2 = MIN(MAX(lon, lons[0]), lons[nlon - 1]);
2795 else
2796 *lon2 = MIN(MAX(lon, lons[nlon - 1]), lons[0]);
2797
2798 *lat2 = lat;
2799 if (lats[0] < lats[nlat - 1])
2800 *lat2 = MIN(MAX(lat, lats[0]), lats[nlat - 1]);
2801 else
2802 *lat2 = MIN(MAX(lat, lats[nlat - 1]), lats[0]);
2803}

◆ intpol_met_4d_zeta()

void intpol_met_4d_zeta ( const met_t met0,
float  height0[EX][EY][EP],
float  array0[EX][EY][EP],
const met_t met1,
float  height1[EX][EY][EP],
float  array1[EX][EY][EP],
const double  ts,
const double  height,
const double  lon,
const double  lat,
double *  var,
int *  ci,
double *  cw,
const int  init 
)

Interpolates meteorological variables to a given position and time.

This function interpolates meteorological variables to a specified position and time. It calculates the interpolated value based on the values provided at two time steps and performs interpolation in time, longitude, latitude, and altitude dimensions.

Parameters
met0Pointer to the meteorological data at the first time step.
height0Array containing heights at the first time step.
array0Array containing meteorological variable values at the first time step.
met1Pointer to the meteorological data at the second time step.
height1Array containing heights at the second time step.
array1Array containing meteorological variable values at the second time step.
tsInterpolation time (fractional time between met0 and met1).
heightAltitude at which to interpolate.
lonLongitude at which to interpolate.
latLatitude at which to interpolate.
varPointer to store the interpolated variable value.
ciArray to store the calculated indices.
cwArray to store the weighting factors.
initFlag indicating if it's the first call (1) or not (0).

The function first restricts the longitude within the range [0, 360) degrees. It then calculates the horizontal indices (ci[0] and ci[1]) based on the provided longitude and latitude. Next, it locates the vertical indices for each edge of the column based on the provided height.

The function then calculates the weighting factors for time, longitude, latitude, and altitude. It iterates over the interpolation process to determine the altitude weighting factor. After initializing the interpolation parameters, it calculates the interpolated variable value and stores it in the memory location pointed to by var.

Note
Ensure that all arrays (height0, array0, height1, array1, ci, cw) have sufficient memory allocated before calling this function.
Author
Jan Clemens

Definition at line 2808 of file mptrac.c.

2822 {
2823
2824 if (init) {
2825
2826 /* Check longitude and latitude... */
2827 double lon2, lat2;
2828
2829 if (met0->coord_type == 0)
2830 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
2831 &lon2, &lat2);
2832 else
2833 intpol_check_cartesian(met0->lon, met0->nx, met0->lat, met0->ny, lon,
2834 lat, &lon2, &lat2);
2835
2836 /* Get horizontal indizes... */
2837 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
2838 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
2839
2840 /* Locate the vertical indizes for each edge of the column... */
2841 int ind[2][4];
2842 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
2843 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
2844
2845 /* Find minimum and maximum indizes... */
2846 ci[2] = ind[0][0];
2847 int k_max = ind[0][0];
2848 for (int i = 0; i < 2; i++)
2849 for (int j = 0; j < 4; j++) {
2850 if (ci[2] > ind[i][j])
2851 ci[2] = ind[i][j];
2852 if (k_max < ind[i][j])
2853 k_max = ind[i][j];
2854 }
2855
2856 /* Get weighting factors for time, longitude and latitude... */
2857 cw[3] = (ts - met0->time) / (met1->time - met0->time);
2858 cw[0] = (lon2 - met0->lon[ci[0]]) /
2859 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
2860 cw[1] = (lat2 - met0->lat[ci[1]]) /
2861 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
2862
2863 /* Interpolate in time at the lowest level... */
2864 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
2865 - heights0[ci[0]][ci[1]][ci[2]])
2866 + heights0[ci[0]][ci[1]][ci[2]];
2867 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
2868 - heights0[ci[0]][ci[1] + 1][ci[2]])
2869 + heights0[ci[0]][ci[1] + 1][ci[2]];
2870 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
2871 - heights0[ci[0] + 1][ci[1]][ci[2]])
2872 + heights0[ci[0] + 1][ci[1]][ci[2]];
2873 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
2874 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
2875 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
2876
2877 /* Interpolate in latitude direction... */
2878 double height0 = cw[1] * (height01 - height00) + height00;
2879 double height1 = cw[1] * (height11 - height10) + height10;
2880
2881 /* Interpolate in longitude direction... */
2882 double height_bot = cw[0] * (height1 - height0) + height0;
2883
2884 /* Interpolate in time at the upper level... */
2885 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2886 - heights0[ci[0]][ci[1]][ci[2] + 1])
2887 + heights0[ci[0]][ci[1]][ci[2] + 1];
2888 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2889 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2890 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2891 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2892 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2893 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2894 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2895 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2896 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2897
2898 /* Interpolate in latitude direction... */
2899 height0 = cw[1] * (height01 - height00) + height00;
2900 height1 = cw[1] * (height11 - height10) + height10;
2901
2902 /* Interpolate in longitude direction... */
2903 double height_top = cw[0] * (height1 - height0) + height0;
2904
2905 /* Search at higher levels if height is not in box... */
2906 while (((heights0[0][0][0] > heights0[0][0][1]) &&
2907 ((height_bot <= height) || (height_top > height))
2908 && (height_bot >= height) && (ci[2] < k_max))
2909 ||
2910 ((heights0[0][0][0] < heights0[0][0][1]) &&
2911 ((height_bot >= height) || (height_top < height))
2912 && (height_bot <= height) && (ci[2] < k_max))
2913 ) {
2914
2915 ci[2]++;
2916 height_bot = height_top;
2917
2918 /* Interpolate in time at the next level... */
2919 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2920 - heights0[ci[0]][ci[1]][ci[2] + 1])
2921 + heights0[ci[0]][ci[1]][ci[2] + 1];
2922 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2923 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2924 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2925 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2926 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2927 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2928 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2929 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2930 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2931
2932 /* Interpolate in latitude direction... */
2933 height0 = cw[1] * (height01 - height00) + height00;
2934 height1 = cw[1] * (height11 - height10) + height10;
2935
2936 /* Interpolate in longitude direction... */
2937 height_top = cw[0] * (height1 - height0) + height0;
2938 }
2939
2940 /* Get vertical weighting factors... */
2941 cw[2] = (height - height_bot)
2942 / (height_top - height_bot);
2943 }
2944
2945 /* Calculate the needed array values... */
2946 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
2947 - array0[ci[0]][ci[1]][ci[2]])
2948 + array0[ci[0]][ci[1]][ci[2]];
2949 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
2950 - array0[ci[0] + 1][ci[1]][ci[2]])
2951 + array0[ci[0] + 1][ci[1]][ci[2]];
2952 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
2953 - array0[ci[0]][ci[1] + 1][ci[2]])
2954 + array0[ci[0]][ci[1] + 1][ci[2]];
2955 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
2956 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
2957 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
2958 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
2959 - array0[ci[0]][ci[1]][ci[2] + 1])
2960 + array0[ci[0]][ci[1]][ci[2] + 1];
2961 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2962 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2963 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2964 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2965 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2966 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2967 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2968 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2969 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2970
2971 const double array00 = cw[0] * (array100 - array000) + array000;
2972 const double array10 = cw[0] * (array110 - array010) + array010;
2973 const double array01 = cw[0] * (array101 - array001) + array001;
2974 const double array11 = cw[0] * (array111 - array011) + array011;
2975
2976 const double aux0 = cw[1] * (array10 - array00) + array00;
2977 const double aux1 = cw[1] * (array11 - array01) + array01;
2978
2979 /* Interpolate vertically... */
2980 *var = cw[2] * (aux1 - aux0) + aux0;
2981}
void intpol_check_cartesian(const double *lons, const int nlon, const double *lats, const int nlat, const double lon, const double lat, double *lon2, double *lat2)
Clamps UTM coordinates to the valid bounds.
Definition: mptrac.c:2782
void locate_vert(float profiles[EX][EY][EP], const int np, const int lon_ap_ind, const int lat_ap_ind, const double height_ap, int *ind)
Locate the four vertical indizes of a box for a given height value.
Definition: mptrac.c:3578
void intpol_check_lon_lat(const double *lons, const int nlon, const double *lats, const int nlat, const double lon, const double lat, double *lon2, double *lat2)
Adjusts longitude and latitude to ensure they fall within valid bounds.
Definition: mptrac.c:2755
int coord_type
Definition: mptrac.h:3852
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3867
int npl
Number of model levels.
Definition: mptrac.h:3864
double time
Time [s].
Definition: mptrac.h:3849
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3870
Here is the call graph for this function:

◆ intpol_met_space_3d()

void intpol_met_space_3d ( const met_t met,
float  array[EX][EY][EP],
const double  p,
const double  lon,
const double  lat,
double *  var,
int *  ci,
double *  cw,
const int  init 
)

Interpolates meteorological variables in 3D space.

This function interpolates meteorological variables at a specified pressure level and geographic position. It calculates the interpolated value based on the values provided at neighboring grid points and performs interpolation in pressure, longitude, and latitude dimensions.

Parameters
metPointer to the meteorological data.
arrayArray containing meteorological variable values.
pPressure level at which to interpolate.
lonLongitude at which to interpolate.
latLatitude at which to interpolate.
varPointer to store the interpolated variable value.
ciArray to store the calculated indices.
cwArray to store the weighting factors.
initFlag indicating if it's the first call (1) or not (0).

The function first checks the longitude and adjusts it if necessary to ensure it falls within the valid range. It then calculates the interpolation indices based on the provided pressure level, longitude, and latitude. Next, it computes the interpolation weights for pressure, longitude, and latitude.

The function interpolates vertically first and then horizontally. The interpolated value is stored in the memory location pointed to by var.

Note
Ensure that the array, ci, and cw arrays have sufficient memory allocated before calling this function.
Author
Lars Hoffmann

Definition at line 2985 of file mptrac.c.

2994 {
2995
2996 /* Initialize interpolation... */
2997 if (init) {
2998
2999 /* Check longitude and latitude... */
3000 double lon2, lat2;
3001
3002 if (met->coord_type == 0)
3003 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
3004 &lon2, &lat2);
3005 else
3006 intpol_check_cartesian(met->lon, met->nx, met->lat, met->ny, lon, lat,
3007 &lon2, &lat2);
3008
3009 /* Get interpolation indices... */
3010 ci[0] = locate_irr(met->p, met->np, p);
3011 ci[1] = locate_reg(met->lon, met->nx, lon2);
3012 ci[2] = locate_irr(met->lat, met->ny, lat2);
3013
3014 /* Get interpolation weights... */
3015 cw[0] = (met->p[ci[0] + 1] - p)
3016 / (met->p[ci[0] + 1] - met->p[ci[0]]);
3017 cw[1] = (met->lon[ci[1] + 1] - lon2)
3018 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
3019 cw[2] = (met->lat[ci[2] + 1] - lat2)
3020 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
3021 }
3022
3023 /* Interpolate vertically... */
3024 const double aux00 =
3025 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
3026 + array[ci[1]][ci[2]][ci[0] + 1];
3027 const double aux01 =
3028 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
3029 array[ci[1]][ci[2] + 1][ci[0] + 1])
3030 + array[ci[1]][ci[2] + 1][ci[0] + 1];
3031 const double aux10 =
3032 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
3033 array[ci[1] + 1][ci[2]][ci[0] + 1])
3034 + array[ci[1] + 1][ci[2]][ci[0] + 1];
3035 const double aux11 =
3036 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
3037 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
3038 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
3039
3040 /* Interpolate horizontally... */
3041 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
3042 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
3043 *var = cw[1] * (aux0 - aux1) + aux1;
3044}
Here is the call graph for this function:

◆ intpol_met_space_2d()

void intpol_met_space_2d ( const met_t met,
float  array[EX][EY],
const double  lon,
const double  lat,
double *  var,
int *  ci,
double *  cw,
const int  init 
)

Interpolates meteorological variables in 2D space.

This function interpolates meteorological variables at a specified geographic position. It calculates the interpolated value based on the values provided at neighboring grid points and performs interpolation in longitude and latitude dimensions.

Parameters
metPointer to the meteorological data.
arrayArray containing meteorological variable values.
lonLongitude at which to interpolate.
latLatitude at which to interpolate.
varPointer to store the interpolated variable value.
ciArray to store the calculated indices.
cwArray to store the weighting factors.
initFlag indicating if it's the first call (1) or not (0).

The function first checks the longitude and adjusts it if necessary to ensure it falls within the valid range. It then calculates the interpolation indices based on the provided longitude and latitude. Next, it computes the interpolation weights for longitude and latitude.

The function interpolates horizontally and stores the interpolated value in the memory location pointed to by var. If any of the data values used in interpolation are not finite, the function handles this situation by choosing a valid value or performing a simple interpolation.

Note
Ensure that the array, ci, and cw arrays have sufficient memory allocated before calling this function.
Author
Lars Hoffmann

Definition at line 3048 of file mptrac.c.

3056 {
3057
3058 /* Initialize interpolation... */
3059 if (init) {
3060
3061 /* Check longitude and latitude... */
3062 double lon2, lat2;
3063
3064 if (met->coord_type == 0)
3065 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
3066 &lon2, &lat2);
3067 else
3068 intpol_check_cartesian(met->lon, met->nx, met->lat, met->ny, lon, lat,
3069 &lon2, &lat2);
3070
3071
3072 /* Get interpolation indices... */
3073 ci[1] = locate_reg(met->lon, met->nx, lon2);
3074 ci[2] = locate_irr(met->lat, met->ny, lat2);
3075
3076 /* Get interpolation weights... */
3077 cw[1] = (met->lon[ci[1] + 1] - lon2)
3078 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
3079 cw[2] = (met->lat[ci[2] + 1] - lat2)
3080 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
3081 }
3082
3083 /* Set variables... */
3084 const double aux00 = array[ci[1]][ci[2]];
3085 const double aux01 = array[ci[1]][ci[2] + 1];
3086 const double aux10 = array[ci[1] + 1][ci[2]];
3087 const double aux11 = array[ci[1] + 1][ci[2] + 1];
3088
3089 /* Interpolate horizontally... */
3090 if (isfinite(aux00) && isfinite(aux01)
3091 && isfinite(aux10) && isfinite(aux11)) {
3092 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
3093 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
3094 *var = cw[1] * (aux0 - aux1) + aux1;
3095 } else {
3096 if (cw[2] < 0.5) {
3097 if (cw[1] < 0.5)
3098 *var = aux11;
3099 else
3100 *var = aux01;
3101 } else {
3102 if (cw[1] < 0.5)
3103 *var = aux10;
3104 else
3105 *var = aux00;
3106 }
3107 }
3108}
Here is the call graph for this function:

◆ intpol_met_time_3d()

void intpol_met_time_3d ( const met_t met0,
float  array0[EX][EY][EP],
const met_t met1,
float  array1[EX][EY][EP],
const double  ts,
const double  p,
const double  lon,
const double  lat,
double *  var,
int *  ci,
double *  cw,
const int  init 
)

Interpolates meteorological data in 3D space and time.

This function interpolates meteorological data in three dimensions (longitude, latitude, and pressure) and time. It calculates the interpolated value based on the values provided at neighboring grid points and performs interpolation both spatially and temporally.

Parameters
met0Pointer to the meteorological data at time t0.
array03D array of meteorological data at time t0.
met1Pointer to the meteorological data at time t1.
array13D array of meteorological data at time t1.
tsTime stamp at which to interpolate.
pPressure level at which to interpolate.
lonLongitude at which to interpolate.
latLatitude at which to interpolate.
varPointer to store the interpolated value.
ciArray to store the calculated indices.
cwArray to store the weighting factors.
initFlag indicating if it's the first call (1) or not (0).

The function first performs spatial interpolation for both time instances (t0 and t1) using the intpol_met_space_3d function. It then calculates the weighting factor wt based on the time stamp ts. Finally, it performs temporal interpolation using the interpolated values at t0 and t1 along with the weighting factor to compute the final interpolated value stored in var.

Note
Ensure that the ci and cw arrays have sufficient memory allocated before calling this function.
Author
Lars Hoffmann

Definition at line 3112 of file mptrac.c.

3124 {
3125
3126 double var0, var1;
3127
3128 /* Spatial interpolation... */
3129 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
3130 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
3131
3132 /* Get weighting factor... */
3133 const double wt = (met1->time - ts) / (met1->time - met0->time);
3134
3135 /* Interpolate... */
3136 *var = wt * (var0 - var1) + var1;
3137}
Here is the call graph for this function:

◆ intpol_met_time_2d()

void intpol_met_time_2d ( const met_t met0,
float  array0[EX][EY],
const met_t met1,
float  array1[EX][EY],
const double  ts,
const double  lon,
const double  lat,
double *  var,
int *  ci,
double *  cw,
const int  init 
)

Interpolates meteorological data in 2D space and time.

This function interpolates meteorological data in two dimensions (longitude and latitude) and time. It calculates the interpolated value based on the values provided at neighboring grid points and performs interpolation both spatially and temporally.

Parameters
met0Pointer to the meteorological data at time t0.
array02D array of meteorological data at time t0.
met1Pointer to the meteorological data at time t1.
array12D array of meteorological data at time t1.
tsTime stamp at which to interpolate.
lonLongitude at which to interpolate.
latLatitude at which to interpolate.
varPointer to store the interpolated value.
ciArray to store the calculated indices.
cwArray to store the weighting factors.
initFlag indicating if it's the first call (1) or not (0).

The function first performs spatial interpolation for both time instances (t0 and t1) using the intpol_met_space_2d function. It then calculates the weighting factor wt based on the time stamp ts. Finally, it performs temporal interpolation using the interpolated values at t0 and t1 along with the weighting factor to compute the final interpolated value stored in var. If one of the interpolated values is not finite, it selects the valid value based on the weighting factor wt.

Note
Ensure that the ci and cw arrays have sufficient memory allocated before calling this function.
Author
Lars Hoffmann

Definition at line 3141 of file mptrac.c.

3152 {
3153
3154 double var0, var1;
3155
3156 /* Spatial interpolation... */
3157 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
3158 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
3159
3160 /* Get weighting factor... */
3161 const double wt = (met1->time - ts) / (met1->time - met0->time);
3162
3163 /* Interpolate... */
3164 if (isfinite(var0) && isfinite(var1))
3165 *var = wt * (var0 - var1) + var1;
3166 else if (wt < 0.5)
3167 *var = var1;
3168 else
3169 *var = var0;
3170}
Here is the call graph for this function:

◆ intpol_tropo_3d()

void intpol_tropo_3d ( const double  time0,
float  array0[EX][EY],
const double  time1,
float  array1[EX][EY],
const double  lons[EX],
const double  lats[EY],
const int  nlon,
const int  nlat,
const double  time,
const double  lon,
const double  lat,
const int  method,
double *  var,
double *  sigma 
)

Interpolates tropopause data in 3D (latitude, longitude, and time).

This function performs interpolation of tropopause data at a given latitude, longitude, and time. The interpolation can be performed using either linear interpolation or nearest neighbor interpolation. The standard deviation of the data points used in the interpolation is also computed.

Parameters
time0Time corresponding to the first data array array0.
array0A 2D array of tropopause data at time0. The dimensions are EX by EY.
time1Time corresponding to the second data array array1.
array1A 2D array of tropopause data at time1. The dimensions are EX by EY.
lonsArray of longitudes with EX elements.
latsArray of latitudes with EY elements.
nlonNumber of longitudes.
nlatNumber of latitudes.
timeThe specific time at which to interpolate the data.
lonThe specific longitude at which to interpolate the data.
latThe specific latitude at which to interpolate the data.
methodInterpolation method: 1 for linear interpolation, otherwise nearest neighbor interpolation is used.
varPointer to the variable where the interpolated value will be stored.
sigmaPointer to the variable where the standard deviation of the data points will be stored.
Precondition
array0 and array1 must be 2D arrays of size EX by EY.
lons must have at least nlon elements and lats must have at least nlat elements.
Postcondition
var will contain the interpolated value.
sigma will contain the standard deviation of the data points used in the interpolation.
Note
The function adjusts the longitude to ensure it is within the range defined by lons.
This function uses the auxiliary functions locate_reg, LIN, and NN for locating indices and performing interpolation.
Warning
Ensure that EX and EY are defined appropriately to match the dimensions of array0 and array1.
Author
Lars Hoffmann

Definition at line 3174 of file mptrac.c.

3188 {
3189
3190 double mean = 0;
3191
3192 int n = 0;
3193
3194 /* Check longitude and latitude... */
3195 double lon2, lat2;
3196 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
3197
3198 /* Get indices... */
3199 const int ix = locate_reg(lons, (int) nlon, lon2);
3200 const int iy = locate_irr(lats, (int) nlat, lat2);
3201
3202 /* Calculate standard deviation... */
3203 *sigma = 0;
3204 for (int dx = 0; dx < 2; dx++)
3205 for (int dy = 0; dy < 2; dy++) {
3206 if (isfinite(array0[ix + dx][iy + dy])) {
3207 mean += array0[ix + dx][iy + dy];
3208 *sigma += SQR(array0[ix + dx][iy + dy]);
3209 n++;
3210 }
3211 if (isfinite(array1[ix + dx][iy + dy])) {
3212 mean += array1[ix + dx][iy + dy];
3213 *sigma += SQR(array1[ix + dx][iy + dy]);
3214 n++;
3215 }
3216 }
3217 if (n > 0)
3218 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
3219
3220 /* Linear interpolation... */
3221 if (method == 1 && isfinite(array0[ix][iy])
3222 && isfinite(array0[ix][iy + 1])
3223 && isfinite(array0[ix + 1][iy])
3224 && isfinite(array0[ix + 1][iy + 1])
3225 && isfinite(array1[ix][iy])
3226 && isfinite(array1[ix][iy + 1])
3227 && isfinite(array1[ix + 1][iy])
3228 && isfinite(array1[ix + 1][iy + 1])) {
3229
3230 const double aux00 = LIN(lons[ix], array0[ix][iy],
3231 lons[ix + 1], array0[ix + 1][iy], lon2);
3232 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
3233 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
3234 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
3235
3236 const double aux10 = LIN(lons[ix], array1[ix][iy],
3237 lons[ix + 1], array1[ix + 1][iy], lon2);
3238 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
3239 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
3240 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
3241
3242 *var = LIN(time0, aux0, time1, aux1, time);
3243 }
3244
3245 /* Nearest neighbor interpolation... */
3246 else {
3247 const double aux00 = NN(lons[ix], array0[ix][iy],
3248 lons[ix + 1], array0[ix + 1][iy], lon2);
3249 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
3250 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
3251 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
3252
3253 const double aux10 = NN(lons[ix], array1[ix][iy],
3254 lons[ix + 1], array1[ix + 1][iy], lon2);
3255 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
3256 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
3257 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
3258
3259 *var = NN(time0, aux0, time1, aux1, time);
3260 }
3261}
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1726
Here is the call graph for this function:

◆ jsec2time()

void jsec2time ( const double  jsec,
int *  year,
int *  mon,
int *  day,
int *  hour,
int *  min,
int *  sec,
double *  remain 
)

Converts Julian seconds to calendar date and time components.

This function converts Julian seconds to calendar date and time components, including year, month, day, hour, minute, and second. It also calculates the fractional part of the seconds.

Parameters
jsecJulian seconds to convert.
yearPointer to store the year.
monPointer to store the month.
dayPointer to store the day.
hourPointer to store the hour.
minPointer to store the minute.
secPointer to store the second.
remainPointer to store the fractional part of seconds.

The function initializes a time structure t0 with a fixed starting date and time. It then converts the Julian seconds to a time_t type by adding the seconds to the epoch time. Next, it converts the time_t value to a UTC time structure t1. Finally, it extracts the year, month, day, hour, minute, and second components from t1 and calculates the fractional part of seconds, which is stored in remain.

Author
Lars Hoffmann

Definition at line 3265 of file mptrac.c.

3273 {
3274
3275 struct tm t0, *t1;
3276
3277 t0.tm_year = 100;
3278 t0.tm_mon = 0;
3279 t0.tm_mday = 1;
3280 t0.tm_hour = 0;
3281 t0.tm_min = 0;
3282 t0.tm_sec = 0;
3283
3284 const time_t jsec0 = (time_t) jsec + timegm(&t0);
3285 t1 = gmtime(&jsec0);
3286
3287 *year = t1->tm_year + 1900;
3288 *mon = t1->tm_mon + 1;
3289 *day = t1->tm_mday;
3290 *hour = t1->tm_hour;
3291 *min = t1->tm_min;
3292 *sec = t1->tm_sec;
3293 *remain = jsec - floor(jsec);
3294}

◆ kernel_weight()

double kernel_weight ( const double  kz[EP],
const double  kw[EP],
const int  nk,
const double  p 
)

Calculates the kernel weight based on altitude and given kernel data.

This function calculates the kernel weight based on altitude and given kernel data. It takes arrays of altitudes (kz) and corresponding weights (kw), the number of data points (nk), and the current altitude (p) as input.

Parameters
kzArray of altitudes.
kwArray of corresponding weights.
nkNumber of data points.
pCurrent altitude.
Returns
The calculated kernel weight.

If the number of data points is less than 2 (nk < 2), the function returns a default weight of 1.0.

The function first computes the altitude z based on the current altitude p. Then it checks whether z is outside the range of altitudes in the kernel data. If so, it returns the corresponding weight at the nearest altitude boundary. Otherwise, it interpolates linearly between the two closest altitudes in the kernel data to determine the weight at altitude z.

Author
Lars Hoffmann

Definition at line 3298 of file mptrac.c.

3302 {
3303
3304 /* Check number of data points... */
3305 if (nk < 2)
3306 return 1.0;
3307
3308 /* Get altitude... */
3309 const double z = Z(p);
3310
3311 /* Get weighting factor... */
3312 if (z < kz[0])
3313 return kw[0];
3314 else if (z > kz[nk - 1])
3315 return kw[nk - 1];
3316 else {
3317 const int idx = locate_irr(kz, nk, z);
3318 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
3319 }
3320}
Here is the call graph for this function:

◆ lapse_rate()

double lapse_rate ( const double  t,
const double  h2o 
)

Calculates the moist adiabatic lapse rate in Kelvin per kilometer.

This function calculates the moist adiabatic lapse rate in Kelvin per kilometer from the given temperature (t) in Kelvin and water vapor volume mixing ratio (h2o).

Parameters
tTemperature in Kelvin.
h2oWater vapor volume mixing ratio.
Returns
The moist adiabatic lapse rate in Kelvin per kilometer.

The moist adiabatic lapse rate is calculated using the formula:

\[ \Gamma = \frac{{1000 \times g \times \left(a + L_v \times r \times T\right)}} {{C_{pd} \times a + L_v^2 \times r \times \epsilon}} \]

where:

  • \( \Gamma \) is the lapse rate in Kelvin per kilometer.
  • \( g \) is the acceleration due to gravity (constant).
  • \( a = R_a \times T^2 \) is a term based on the gas constant for dry air and temperature squared.
  • \( R_a \) is the gas constant for dry air.
  • \( T \) is the temperature in Kelvin.
  • \( L_v \) is the latent heat of vaporization.
  • \( r = \frac{{S_h(h_2o)}}{{1 - S_h(h_2o)}} \) is a term based on the water vapor mixing ratio.
  • \( S_h(h_2o) \) is the saturation vapor pressure relative to the pressure at saturation.
  • \( C_{pd} \) is the specific heat of dry air at constant pressure.
  • \( \epsilon \) is the ratio of the gas constants for dry air and water vapor.

The constants used in the calculation are defined externally:

  • \( g \): Acceleration due to gravity (constant).
  • \( R_a \): Gas constant for dry air.
  • \( L_v \): Latent heat of vaporization.
  • \( C_{pd} \): Specific heat of dry air at constant pressure.
  • \( \epsilon \): Ratio of the gas constants for dry air and water vapor.
See also
Wikipedia - Lapse rate
Author
Lars Hoffmann

Definition at line 3324 of file mptrac.c.

3326 {
3327
3328 /*
3329 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
3330 and water vapor volume mixing ratio [1].
3331
3332 Reference: https://en.wikipedia.org/wiki/Lapse_rate
3333 */
3334
3335 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
3336
3337 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
3338}
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:309
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:2023
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:274
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:264
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:259
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:254

◆ level_definitions()

void level_definitions ( ctl_t ctl)

Defines pressure levels for meteorological data.

This function defines pressure levels for meteorological data based on the given control structure (ctl). Pressure levels are defined differently based on the value of met_press_level_def in ctl.

Parameters
ctlControl structure containing information about pressure level definitions.

The function determines the number of pressure levels (met_np) and the corresponding pressure values (met_p) based on the value of met_press_level_def in the control structure ctl. It initializes the met_np and met_p fields accordingly.

Note
Valid values for met_press_level_def are:
  • 3: Define 147 pressure levels.
  • 4: Define 101 pressure levels.
  • 5: Define 62 pressure levels.
  • 6: Define 137 pressure levels.
  • 7: Define 59 pressure levels. Values 0, 1, and 2 are disabled and any other value will result in an error message.
Author
Jan Clemens

Definition at line 3342 of file mptrac.c.

3343 {
3344
3345 if (0 == ctl->met_press_level_def) {
3346
3347 ERRMSG
3348 ("MET_PRESS_LEVEL_DEF=0 is disabled. Use 3 for the extended L137 set.");
3349
3350 } else if (1 == ctl->met_press_level_def) {
3351
3352 ERRMSG
3353 ("MET_PRESS_LEVEL_DEF=1 is disabled. Use 4 for the extended L91 set.");
3354
3355 } else if (2 == ctl->met_press_level_def) {
3356
3357 ERRMSG
3358 ("MET_PRESS_LEVEL_DEF=2 is disabled. Use 5 for the extended L60 set.");
3359
3360 } else if (3 == ctl->met_press_level_def) {
3361
3362 ctl->met_np = 147;
3363
3364 const double press[147] = {
3365 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
3366 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
3367 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
3368 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
3369 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
3370 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
3371 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
3372 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
3373 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
3374 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
3375 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
3376 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
3377 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
3378 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
3379 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
3380 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
3381 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
3382 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
3383 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
3384 1031.97,
3385 1035.09, 1038.21, 1041.33, 1044.45
3386 };
3387
3388 for (int ip = 0; ip < ctl->met_np; ip++)
3389 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3390
3391 } else if (4 == ctl->met_press_level_def) {
3392
3393 ctl->met_np = 101;
3394
3395 const double press[101] = {
3396 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
3397 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
3398 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
3399 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
3400 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
3401 113.6382,
3402 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
3403 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
3404 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
3405 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
3406 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
3407 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
3408 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
3409 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
3410 1028.85, 1031.97,
3411 1035.09, 1038.21, 1041.33, 1044.45
3412 };
3413
3414 for (int ip = 0; ip < ctl->met_np; ip++)
3415 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3416
3417 } else if (5 == ctl->met_press_level_def) {
3418
3419 ctl->met_np = 62;
3420
3421 const double press[62] = {
3422 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
3423 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
3424 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
3425 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
3426 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
3427 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
3428 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
3429 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
3430 1044.45
3431 };
3432
3433 for (int ip = 0; ip < ctl->met_np; ip++)
3434 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3435
3436 } else if (6 == ctl->met_press_level_def) {
3437
3438 ctl->met_np = 137;
3439
3440 const double press[137] = {
3441 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
3442 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
3443 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
3444 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
3445 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
3446 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
3447 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
3448 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
3449 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
3450 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
3451 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
3452 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
3453 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
3454 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
3455 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
3456 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
3457 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
3458 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
3459 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
3460 1030.06, 1037.25, 1044.45
3461 };
3462
3463 for (int ip = 0; ip < ctl->met_np; ip++)
3464 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3465
3466 } else if (7 == ctl->met_press_level_def) {
3467
3468 ctl->met_np = 59;
3469
3470 const double press[59] = {
3471 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
3472 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
3473 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
3474 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
3475 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
3476 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
3477 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
3478 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
3479 1028.53, 1046.13
3480 };
3481
3482 for (int ip = 0; ip < ctl->met_np; ip++)
3483 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3484
3485 } else {
3486 ERRMSG("Use values between 3 and 7.");
3487 }
3488
3489 if (ctl->met_np > EP)
3490 ERRMSG("Recompile with larger EP to use this pressure level definition!");
3491}
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2956
int met_np
Number of target pressure levels.
Definition: mptrac.h:2950
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2953

◆ locate_irr()

int locate_irr ( const double *  xx,
const int  n,
const double  x 
)

Locate the index of the interval containing a given value in a sorted array.

This function locates the index of the interval containing a given value in a sorted array. It uses a binary search algorithm to efficiently find the interval.

Parameters
xxPointer to the sorted array.
nSize of the array.
xValue to be located.
Returns
Index of the interval containing the value x.

The function assumes that the array xx is sorted in ascending order. It returns the index of the interval where the value x is located. If the value x is outside the range of the array, the function returns the index of the closest interval.

Author
Lars Hoffmann

Definition at line 3495 of file mptrac.c.

3498 {
3499
3500 int ilo = 0;
3501 int ihi = n - 1;
3502 int i = (ihi + ilo) >> 1;
3503
3504 if (xx[i] < xx[i + 1])
3505 while (ihi > ilo + 1) {
3506 i = (ihi + ilo) >> 1;
3507 if (xx[i] > x)
3508 ihi = i;
3509 else
3510 ilo = i;
3511 } else
3512 while (ihi > ilo + 1) {
3513 i = (ihi + ilo) >> 1;
3514 if (xx[i] <= x)
3515 ihi = i;
3516 else
3517 ilo = i;
3518 }
3519
3520 return ilo;
3521}

◆ locate_irr_float()

int locate_irr_float ( const float *  xx,
const int  n,
const double  x,
const int  ig 
)

Locate the index of the interval containing a given value in an irregularly spaced array.

This function performs a binary search to locate the interval in the array xx such that xx[ig] <= x < xx[ig + 1]. If the value x lies within the interval specified by the initial guess index ig, the function returns ig. Otherwise, it searches the array to find the correct interval.

Parameters
xxPointer to the array of floats representing the irregularly spaced intervals. The array must be of size n.
nThe number of elements in the array xx.
xThe value to locate within the intervals of the array xx.
igThe initial guess index. If the interval [xx[ig], xx[ig+1]) contains x, the function returns ig directly.
Returns
The index i such that xx[i] <= x < xx[i + 1]. If x is out of bounds, it returns the index of the closest interval.
Note
The function assumes that the array xx contains at least two elements.
The function can handle both increasing and decreasing sequences in the array xx.
Warning
The behavior is undefined if the array xx is not sorted in either increasing or decreasing order, or if it contains less than two elements.
Author
Lars Hoffmann

Definition at line 3525 of file mptrac.c.

3529 {
3530
3531 int ilo = 0;
3532 int ihi = n - 1;
3533 int i = (ihi + ilo) >> 1;
3534
3535 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
3536 return ig;
3537
3538 if (xx[i] < xx[i + 1])
3539 while (ihi > ilo + 1) {
3540 i = (ihi + ilo) >> 1;
3541 if (xx[i] > x)
3542 ihi = i;
3543 else
3544 ilo = i;
3545 } else
3546 while (ihi > ilo + 1) {
3547 i = (ihi + ilo) >> 1;
3548 if (xx[i] <= x)
3549 ihi = i;
3550 else
3551 ilo = i;
3552 }
3553
3554 return ilo;
3555}

◆ locate_reg()

int locate_reg ( const double *  xx,
const int  n,
const double  x 
)

Locate the index of the interval containing a given value in a regular grid.

This function locates the index of the interval containing a given value in a regular grid. It calculates the index based on the spacing between grid points and the value to be located.

Parameters
xxPointer to the array representing the regular grid.
nSize of the grid (number of grid points).
xValue to be located.
Returns
Index of the interval containing the value x.

The function assumes that the array xx represents a regular grid with equally spaced points. It calculates the index of the interval where the value x is located based on the spacing between grid points. If the value x is outside the range of the grid, the function returns the index of the closest interval.

Author
Lars Hoffmann

Definition at line 3559 of file mptrac.c.

3562 {
3563
3564 /* Calculate index... */
3565 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
3566
3567 /* Check range... */
3568 if (i < 0)
3569 return 0;
3570 else if (i > n - 2)
3571 return n - 2;
3572 else
3573 return i;
3574}

◆ locate_vert()

void locate_vert ( float  profiles[EX][EY][EP],
const int  np,
const int  lon_ap_ind,
const int  lat_ap_ind,
const double  alt_ap,
int *  ind 
)

Locate the four vertical indizes of a box for a given height value.

This function locates the vertical indices corresponding to a given height in a 3D irregular grid. It calculates the indices based on the specified longitude and latitude indices of the grid.

Parameters
profiles3D array representing the irregular grid.
npSize of the profile (number of data points).
lon_ap_indIndex of the longitude.
lat_ap_indIndex of the latitude.
alt_apHeight value.
indPointer to an array to store the resulting indices.

The function calculates the indices corresponding to the specified height in the 3D irregular grid. It stores the resulting indices in the array pointed to by ind. The indices are calculated based on the specified longitude and latitude indices of the grid.

Author
Lars Hoffmann

Definition at line 3578 of file mptrac.c.

3584 {
3585
3586 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
3587 np, height_ap, 0);
3588 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
3589 np, height_ap, ind[0]);
3590 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
3591 np, height_ap, ind[1]);
3592 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
3593 np, height_ap, ind[2]);
3594}
int locate_irr_float(const float *xx, const int n, const double x, const int ig)
Locate the index of the interval containing a given value in an irregularly spaced array.
Definition: mptrac.c:3525
Here is the call graph for this function:

◆ module_advect()

void module_advect ( const ctl_t ctl,
const cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Advances particle positions using different advection schemes.

This function updates the positions of atmospheric particles using different advection schemes based on vertical velocity formulations (omega or zetadot). The advection is performed over a number of integration nodes, using meteorological data interpolated in time and space.

Parameters
[in]ctlPointer to the control structure containing configuration settings.
[in]cachePointer to the cache structure storing precomputed time step values.
[in]met0Pointer to the meteorological data structure at the initial time.
[in]met1Pointer to the meteorological data structure at the next time step.
[in,out]atmPointer to the atmospheric data structure containing particle states.
  • If ctl->advect_vert_coord is 0 or 2, the function uses omega vertical velocity.
  • If ctl->advect_vert_coord is 1, the function uses zetadot vertical velocity.
  • The function interpolates meteorological data either on pressure levels or model levels.
  • The advection scheme supports different integration methods (e.g., two-stage, four-stage).
  • The function updates longitude, latitude, and pressure (or zeta) for each particle.
  • Special handling is applied to ensure zeta values remain non-negative.
Author
Lars Hoffmann
Jan Clemens

Definition at line 3598 of file mptrac.c.

3603 {
3604
3605 /* Set timer... */
3606 SELECT_TIMER("MODULE_ADVECT", "PHYSICS");
3607
3608 /* Use omega vertical velocity... */
3609 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
3610
3611 /* Loop over particles... */
3612 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3613
3614 /* Init... */
3616 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
3617 x[3] = { 0, 0, 0 };
3618
3619 /* Loop over integration nodes... */
3620 for (int i = 0; i < ctl->advect; i++) {
3621
3622 /* Set position... */
3623 if (i == 0) {
3624 dts = 0.0;
3625 x[0] = atm->lon[ip];
3626 x[1] = atm->lat[ip];
3627 x[2] = atm->p[ip];
3628 } else {
3629 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3630 x[0] = atm->lon[ip] + DX2COORD(met0, dts * u[i - 1], atm->lat[ip]);
3631 x[1] = atm->lat[ip] + DY2COORD(met0, dts * v[i - 1]);
3632 x[2] = atm->p[ip] + dts * w[i - 1];
3633 }
3634 const double tm = atm->time[ip] + dts;
3635
3636 /* Interpolate meteo data on pressure levels... */
3637 if (ctl->advect_vert_coord == 0) {
3638 intpol_met_time_3d(met0, met0->u, met1, met1->u,
3639 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3640 intpol_met_time_3d(met0, met0->v, met1, met1->v,
3641 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3642 intpol_met_time_3d(met0, met0->w, met1, met1->w,
3643 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3644 }
3645
3646 /* Interpolate meteo data on model levels... */
3647 else {
3648 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
3649 met1, met1->pl, met1->ul,
3650 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3651 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
3652 met1, met1->pl, met1->vl,
3653 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3654 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
3655 met1, met1->pl, met1->wl,
3656 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3657 }
3658
3659 /* Get mean wind... */
3660 double k = 1.0;
3661 if (ctl->advect == 2)
3662 k = (i == 0 ? 0.0 : 1.0);
3663 else if (ctl->advect == 4)
3664 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3665 um += k * u[i];
3666 vm += k * v[i];
3667 wm += k * w[i];
3668 }
3669
3670 /* Set new position... */
3671 atm->time[ip] += cache->dt[ip];
3672 atm->lon[ip] += DX2COORD(met0, cache->dt[ip] * um,
3673 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3674 atm->lat[ip] += DY2COORD(met0, cache->dt[ip] * vm);
3675 atm->p[ip] += cache->dt[ip] * wm;
3676
3677 }
3678 }
3679
3680 /* Use zeta or eta vertical velocity... */
3681 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
3682
3683 /* Select quantity index depending on coordinate... */
3684 const int qnt = (ctl->advect_vert_coord == 1
3685 ? ctl->qnt_zeta : ctl->qnt_eta);
3686
3687 /* Loop over particles... */
3688 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3689
3690 /* Convert pressure to vertical coordinate (zeta or eta)... */
3692 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
3693 met1, met1->pl, met1->zetal,
3694 atm->time[ip], atm->p[ip],
3695 atm->lon[ip], atm->lat[ip],
3696 &atm->q[qnt][ip], ci, cw, 1);
3697
3698 /* Init... */
3699 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
3700 wdotm = 0, x[3] = { 0, 0, 0 };
3701
3702 /* Loop over integration nodes (Runge–Kutta steps)... */
3703 for (int i = 0; i < ctl->advect; i++) {
3704
3705 /* Set position... */
3706 if (i == 0) {
3707 dts = 0.0;
3708 x[0] = atm->lon[ip];
3709 x[1] = atm->lat[ip];
3710 x[2] = atm->q[qnt][ip];
3711 } else {
3712 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3713 x[0] = atm->lon[ip] + DX2COORD(met0, dts * u[i - 1], atm->lat[ip]);
3714 x[1] = atm->lat[ip] + DY2COORD(met0, dts * v[i - 1]);
3715 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
3716 }
3717
3718 const double tm = atm->time[ip] + dts;
3719
3720 /* Interpolate meteo data... */
3721 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
3722 met1, met1->zetal, met1->ul,
3723 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3724 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
3725 met1, met1->zetal, met1->vl,
3726 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3727 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
3728 met1, met1->zetal, met1->zeta_dotl,
3729 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
3730
3731 /* Compute Runge–Kutta weights... */
3732 double k = 1.0;
3733 if (ctl->advect == 2)
3734 k = (i == 0 ? 0.0 : 1.0);
3735 else if (ctl->advect == 4)
3736 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3737
3738 um += k * u[i];
3739 vm += k * v[i];
3740 wdotm += k * wdot[i];
3741 }
3742
3743 /* Update particle position... */
3744 atm->time[ip] += cache->dt[ip];
3745 atm->lon[ip] += DX2COORD(met0, cache->dt[ip] * um,
3746 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3747 atm->lat[ip] += DY2COORD(met0, cache->dt[ip] * vm);
3748 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
3749
3750 /* Convert vertical coordinate (zeta or eta) back to pressure... */
3751 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
3752 met1, met1->zetal, met1->pl,
3753 atm->time[ip],
3754 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
3755 &atm->p[ip], ci, cw, 1);
3756 }
3757 }
3758}
void intpol_met_time_3d(const met_t *met0, float array0[EX][EY][EP], const met_t *met1, float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological data in 3D space and time.
Definition: mptrac.c:3112
void intpol_met_4d_zeta(const met_t *met0, float heights0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float heights1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double height, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological variables to a given position and time.
Definition: mptrac.c:2808
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1753
#define SELECT_TIMER(id, group)
Select and start a timer with specific attributes.
Definition: mptrac.h:2479
#define DX2COORD(met, dx, lat)
Convert a distance in meters to a coordinate value based on grid type.
Definition: mptrac.h:965
#define DY2COORD(met, dy)
Convert a distance to coordinate value based on grid type.
Definition: mptrac.h:988
double time[NP]
Time [s].
Definition: mptrac.h:3571
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3580
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3577
int np
Number of air parcels.
Definition: mptrac.h:3568
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3583
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3574
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3641
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2716
int advect
Advection scheme (1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:3025
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2707
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:3029
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:4014
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3972
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:4008
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:4005
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3966
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:4002
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3969
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3999
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:4011
Here is the call graph for this function:

◆ module_advect_init()

void module_advect_init ( const ctl_t ctl,
const cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Initializes the advection module by setting up pressure fields.

This function initializes the advection module, setting up the air parcel pressure to be consistent with the given zeta vertical coordinate. It utilizes meteorological data from two time steps and interpolates the pressure values accordingly.

Parameters
ctlPointer to the control structure containing configuration flags.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the initial meteorological data structure.
met1Pointer to the final meteorological data structure.
atmPointer to the air parcel data structure.

The function performs the following operations:

  • Sets up a timer labeled "MODULE_ADVECT_INIT" within the "PHYSICS" category.
  • If the zeta vertical coordinate system is specified (ctl->vert_coord_ap == 1), it initializes the pressure fields to be consistent with the zeta coordinate using 4D interpolation.
Author
Jan Clemens

Definition at line 3762 of file mptrac.c.

3767 {
3768
3769 /* Check parameters... */
3770 if (ctl->advect_vert_coord != 1)
3771 return;
3772
3773 /* Set timer... */
3774 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS");
3775
3776 /* Loop over particles... */
3777 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
3778
3779 /* Initialize pressure consistent with zeta... */
3781 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
3782 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
3783 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
3784 }
3785}
Here is the call graph for this function:

◆ module_bound_cond()

void module_bound_cond ( const ctl_t ctl,
const cache_t cache,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm 
)

Apply boundary conditions to particles based on meteorological and climatological data.

This function applies boundary conditions to particles based on specified criteria, including latitude, pressure, surface layer parameters, and climatological data. It loops over each particle and checks whether it satisfies the specified boundary conditions. If a particle satisfies the conditions, its properties such as mass, volume mixing ratio, and age of air are updated accordingly.

It checks for quantity flags to determine which properties need to be updated. If the latitude or pressure of a particle falls outside the specified ranges, it skips the particle. It also considers surface layer parameters such as surface pressure, height, zeta range, and planetary boundary layer. If a particle is within the specified surface layer boundaries, its properties are updated accordingly.

The function updates properties such as mass and volume mixing ratio if the corresponding flags are set. It retrieves volume mixing ratio values for various trace gases (e.g., CFC-10, CFC-11, N2O, SF6) from climatological time series data and updates the particle properties accordingly. Additionally, it updates the age of air for each particle based on the current simulation time.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climatological data structure containing time series data.
met0Pointer to the meteorological data structure at the initial time step.
met1Pointer to the meteorological data structure at the next time step.
atmPointer to the atmospheric data structure containing particle information.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 3789 of file mptrac.c.

3795 {
3796
3797 /* Set timer... */
3798 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS");
3799
3800 /* Check quantity flags... */
3801 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
3802 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
3803 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
3804 return;
3805
3806 /* Loop over particles... */
3807 PARTICLE_LOOP(0, atm->np, 1,
3808 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3809
3810 /* Check latitude and pressure range... */
3811 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
3812 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
3813 continue;
3814
3815 /* Check surface layer... */
3816 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
3817 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
3818
3819 /* Get surface pressure... */
3820 double ps;
3822 INTPOL_2D(ps, 1);
3823
3824 /* Check pressure... */
3825 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
3826 continue;
3827
3828 /* Check height... */
3829 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
3830 continue;
3831
3832 /* Check zeta range... */
3833 if (ctl->bound_zetas > 0) {
3834 double t;
3835 INTPOL_3D(t, 1);
3836 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
3837 continue;
3838 }
3839
3840 /* Check planetary boundary layer... */
3841 if (ctl->bound_pbl) {
3842 double pbl;
3843 INTPOL_2D(pbl, 0);
3844 if (atm->p[ip] < pbl)
3845 continue;
3846 }
3847 }
3848
3849 /* Set mass and volume mixing ratio... */
3850 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
3851 atm->q[ctl->qnt_m][ip] =
3852 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
3853 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
3854 atm->q[ctl->qnt_vmr][ip] =
3855 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
3856
3857 /* Set CFC-10 volume mixing ratio... */
3858 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
3859 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
3860
3861 /* Set CFC-11 volume mixing ratio... */
3862 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
3863 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
3864
3865 /* Set CFC-12 volume mixing ratio... */
3866 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
3867 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
3868
3869 /* Set N2O volume mixing ratio... */
3870 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
3871 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
3872
3873 /* Set SF6 volume mixing ratio... */
3874 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
3875 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
3876
3877 /* Set age of air... */
3878 if (ctl->qnt_aoa >= 0)
3879 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
3880 }
3881}
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:396
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:1204
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:2292
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:1187
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3829
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3835
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3823
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3826
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3832
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2788
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2524
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2797
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:3161
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:3110
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2782
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:3083
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2527
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:3098
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:3116
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:3104
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:3089
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:3095
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:3092
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2791
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2785
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2794
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:3107
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:3086
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:3101
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:3152
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:3164
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:3155
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:3158
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:3113
Here is the call graph for this function:

◆ module_chem_grid()

void module_chem_grid ( const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
const double  t 
)

Computes gridded chemical tracer concentrations (volume mixing ratio) from individual air parcel mass data and assigns them back to the parcels.

This function aggregates the mass of tracer particles onto a 3D chemical grid (longitude × latitude × altitude), accounting for either single or ensemble simulations depending on ctl->nens. It then interpolates meteorological temperature fields and computes volume mixing ratios, storing them in the specified tracer quantity (e.g., ctl->qnt_Cx).

If the molar mass is undefined or required quantity indices are missing, the function exits early.

Parallelization is supported via OpenMP or OpenACC.

Parameters
[in]ctlPointer to the control structure containing configuration parameters, including grid dimensions, tracer indices, and simulation mode.
[in]met0Pointer to the meteorological data at the beginning of the interpolation interval.
[in]met1Pointer to the meteorological data at the end of the interpolation interval.
[in,out]atmPointer to the atmospheric state, including parcel coordinates, time, mass, and output tracer fields.
[in]tCentral time step used for output and interpolation.
Note
  • Requires ctl->molmass > 0, and ctl->qnt_m and ctl->qnt_Cx to be set.
  • Uses ensemble mode if ctl->nens > 0 and assigns each parcel to its ensemble member via ctl->qnt_ens.
  • Grid box volume mixing ratios are computed assuming ideal gas law and a layered spherical grid.
  • The output quantity (e.g., qnt_Cx) is given in ppbv.
See also
intpol_met_time_3d()
P(), Z(), RHO()
ARRAY_3D macro
Author
Mingzhao Liu
Lars Hoffmann

Definition at line 3885 of file mptrac.c.

3890 {
3891
3892 if (met0->coord_type != 0)
3893 ERRMSG("Only lat/lon grid supported");
3894
3895 /* Check quantities... */
3896 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
3897 return;
3898 if (ctl->molmass <= 0)
3899 ERRMSG("Molar mass is not defined!");
3900
3901 /* Set timer... */
3902 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS");
3903
3904 /* Allocate... */
3905 const int ensemble_mode = (ctl->nens > 0);
3906 const int np = atm->np;
3907 const int nz = ctl->chemgrid_nz;
3908 const int nx = ctl->chemgrid_nx;
3909 const int ny = ctl->chemgrid_ny;
3910 const int ngrid = nx * ny * nz;
3911 const int nens = ensemble_mode ? ctl->nens : 1;
3912
3913 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
3914 double *restrict const press =
3915 (double *) malloc((size_t) nz * sizeof(double));
3916 double *restrict const mass =
3917 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
3918 double *restrict const area =
3919 (double *) malloc((size_t) ny * sizeof(double));
3920 double *restrict const lon =
3921 (double *) malloc((size_t) nx * sizeof(double));
3922 double *restrict const lat =
3923 (double *) malloc((size_t) ny * sizeof(double));
3924
3925 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3926 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3927 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3928
3929 /* Set grid box size... */
3930 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
3931 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
3932 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
3933
3934 /* Set vertical coordinates... */
3935#ifdef _OPENACC
3936#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np],z[0:nz],press[0:nz],mass[0:ngrid*nens],area[0:ny],lon[0:nx],lat[0:ny])
3937#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
3938#pragma acc parallel loop independent gang vector
3939#else
3940#pragma omp parallel for default(shared)
3941#endif
3942 for (int iz = 0; iz < nz; iz++) {
3943 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
3944 press[iz] = P(z[iz]);
3945 }
3946
3947 /* Set time interval for output... */
3948 const double t0 = tt - 0.5 * ctl->dt_mod;
3949 const double t1 = tt + 0.5 * ctl->dt_mod;
3950
3951 /* Get indices... */
3952#ifdef _OPENACC
3953#pragma acc parallel loop independent gang vector
3954#else
3955#pragma omp parallel for default(shared)
3956#endif
3957 for (int ip = 0; ip < np; ip++) {
3958 const double zpart = Z(atm->p[ip]);
3959 if (atm->time[ip] < t0 || atm->time[ip] > t1
3960 || atm->lon[ip] < ctl->chemgrid_lon0
3961 || atm->lon[ip] >= ctl->chemgrid_lon1
3962 || atm->lat[ip] < ctl->chemgrid_lat0
3963 || atm->lat[ip] >= ctl->chemgrid_lat1
3964 || zpart < ctl->chemgrid_z0 || zpart >= ctl->chemgrid_z1) {
3965 izs[ip] = -1;
3966 continue;
3967 }
3968 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
3969 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
3970 izs[ip] = (int) ((zpart - ctl->chemgrid_z0) / dz);
3971 if (ixs[ip] >= nx || iys[ip] >= ny || izs[ip] >= nz)
3972 izs[ip] = -1;
3973 }
3974
3975 /* Set horizontal coordinates... */
3976#ifdef _OPENACC
3977#pragma acc parallel loop independent gang vector
3978#else
3979#pragma omp parallel for default(shared)
3980#endif
3981 for (int ix = 0; ix < nx; ix++)
3982 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3983
3984#ifdef _OPENACC
3985#pragma acc parallel loop independent gang vector
3986#else
3987#pragma omp parallel for default(shared)
3988#endif
3989 for (int iy = 0; iy < ny; iy++) {
3990 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3991 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3992 }
3993
3994 /* Get mass per grid box... */
3995#ifdef _OPENACC
3996#pragma acc parallel loop independent gang vector
3997#endif
3998 for (int ip = 0; ip < np; ip++) {
3999 if (izs[ip] >= 0) {
4000 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
4001 if (ensemble_mode) {
4002 const int ens = (int) atm->q[ctl->qnt_ens][ip];
4003 mass_idx += ens * ngrid;
4004 }
4005#ifdef _OPENACC
4006#pragma acc atomic update
4007#endif
4008 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
4009 }
4010 }
4011
4012 /* Assign grid data to air parcels ... */
4013#ifdef _OPENACC
4014#pragma acc parallel loop independent gang vector
4015#else
4016#pragma omp parallel for default(shared)
4017#endif
4018 for (int ip = 0; ip < np; ip++)
4019 if (izs[ip] >= 0) {
4020
4021 /* Interpolate temperature... */
4022 double temp;
4024 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
4025 press[izs[ip]],
4026 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
4027
4028 /* Set mass... */
4029 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
4030 if (ensemble_mode) {
4031 const int ens = (int) atm->q[ctl->qnt_ens][ip];
4032 mass_idx += ens * ngrid;
4033 }
4034
4035 /* Calculate volume mixing ratio... */
4036 const double m = mass[mass_idx];
4037 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
4038 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
4039 }
4040
4041 /* Free... */
4042#ifdef _OPENACC
4043#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
4044#endif
4045 free(mass);
4046 free(lon);
4047 free(lat);
4048 free(area);
4049 free(z);
4050 free(press);
4051 free(ixs);
4052 free(iys);
4053 free(izs);
4054}
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:708
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:289
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1783
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1960
double molmass
Molar mass [g/mol].
Definition: mptrac.h:3122
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:3209
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:3206
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:3224
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:3227
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:3215
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:3218
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2833
int nens
Number of ensembles.
Definition: mptrac.h:3390
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:3203
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:3212
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:3221
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2518
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2752
Here is the call graph for this function:

◆ module_chem_init()

void module_chem_init ( const ctl_t ctl,
const cache_t cache,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm 
)

Initializes the chemistry modules by setting atmospheric composition.

This function initializes various chemical components of the atmosphere using meteorological data and climatological information. It interpolates and sets values for water vapor (H2O), ozone (O3), and several radical species such as OH, HO2, H2O2, and O1D for each air parcel.

Parameters
ctlPointer to the control structure containing quantity flags.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climatology structure containing climatological data.
met0Pointer to the initial meteorological data structure.
met1Pointer to the final meteorological data structure.
atmPointer to the air parcel data structure.

The function uses OpenMP for parallel processing, iterating over each point in the atmosphere (atm->np) to initialize chemical species concentrations. It performs the following steps:

  • Interpolates H2O and O3 data from meteorological input if the respective quantity flags (ctl->qnt_Ch2o and ctl->qnt_Co3) are set.
  • Sets the concentrations of OH, HO2, H2O2, and O1D using climatological data if the respective quantity flags are set.
Author
Mingzhao Liu

Definition at line 4058 of file mptrac.c.

4064 {
4065
4066 /* Set timer... */
4067 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS");
4068
4069 /* Loop over particles... */
4070 PARTICLE_LOOP(0, atm->np, 0,
4071 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4072
4073 /* Set H2O and O3 using meteo data... */
4075 if (ctl->qnt_Ch2o >= 0) {
4076 double h2o;
4077 INTPOL_3D(h2o, 1);
4078 SET_ATM(qnt_Ch2o, h2o);
4079 }
4080 if (ctl->qnt_Co3 >= 0) {
4081 double o3;
4082 INTPOL_3D(o3, 1);
4083 SET_ATM(qnt_Co3, o3);
4084 }
4085
4086 /* Set radical species... */
4087 const double lat_ref =
4088 ctl->met_coord_type == 0 ? atm->lat[ip] : ctl->met_utm_ref_lat;
4089 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
4090 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4091 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
4092 lat_ref, atm->p[ip]));
4093 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
4094 lat_ref, atm->p[ip]));
4095 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
4096 lat_ref, atm->p[ip]));
4097 }
4098}
double clim_oh(const ctl_t *ctl, const clim_t *clim, const double t, const double lon, const double lat, const double p)
Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal co...
Definition: mptrac.c:89
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1979
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3817
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3820
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3814
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2755
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2758
Here is the call graph for this function:

◆ module_convection()

void module_convection ( const ctl_t ctl,
cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Performs convective mixing of atmospheric particles.

This function adjusts the pressure of atmospheric particles based on boundary layer (PBL) mixing and convective conditions driven by CAPE (Convective Available Potential Energy) and CIN (Convective Inhibition). It uses meteorological data and random numbers for vertical mixing calculations.

Parameters
[in]ctlPointer to the control structure with simulation settings.
[in,out]cachePointer to the cache structure for temporary data and random numbers.
[in,out]met0Pointer to the meteorological data at the initial timestep.
[in,out]met1Pointer to the meteorological data at the subsequent timestep.
[in,out]atmPointer to the atmospheric data structure with particle properties.
Note
  • This function modifies the atm structure in place.
  • Interpolates CAPE, CIN, and other meteorological parameters.
  • Determines the pressure range for PBL and convective mixing.
  • Updates the pressure of particles based on calculated mixing.
Author
Lars Hoffmann

Definition at line 4102 of file mptrac.c.

4107 {
4108
4109 /* Set timer... */
4110 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS");
4111
4112 /* Create random numbers... */
4113 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
4114
4115 /* Loop over particles... */
4116 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4117
4118 /* Interpolate surface pressure... */
4119 double ps;
4121 INTPOL_2D(ps, 1);
4122
4123 /* Initialize pressure range for vertical mixing... */
4124 double pbot = ps, ptop = ps;
4125
4126 /* Mixing in the PBL... */
4127 if (ctl->conv_mix_pbl) {
4128
4129 /* Interpolate PBL... */
4130 double pbl;
4131 INTPOL_2D(pbl, 0);
4132
4133 /* Set pressure range... */
4134 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
4135 }
4136
4137 /* Convective mixing... */
4138 if (ctl->conv_cape >= 0) {
4139
4140 /* Interpolate CAPE, CIN, and equilibrium level... */
4141 double cape, cin, pel;
4142 INTPOL_2D(cape, 0);
4143 INTPOL_2D(cin, 0);
4144 INTPOL_2D(pel, 0);
4145
4146 /* Set pressure range... */
4147 if (isfinite(cape) && cape >= ctl->conv_cape
4148 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
4149 ptop = MIN(ptop, pel);
4150 }
4151
4152 /* Apply vertical mixing... */
4153 if (ptop != pbot && atm->p[ip] >= ptop) {
4154
4155 /* Get density range... */
4156 double tbot, ttop;
4157 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
4158 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
4159 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
4160 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
4161 const double rhobot = pbot / tbot;
4162 const double rhotop = ptop / ttop;
4163
4164 /* Get new density... */
4165 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
4166
4167 /* Get pressure... */
4168 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
4169 }
4170 }
4171}
void module_rng(const ctl_t *ctl, double *rs, const size_t n, const int method)
Generate random numbers using various methods and distributions.
Definition: mptrac.c:5774
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3638
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:3074
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL pressure thickness).
Definition: mptrac.h:3071
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:3068
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:3077
Here is the call graph for this function:

◆ module_decay()

void module_decay ( const ctl_t ctl,
const cache_t cache,
const clim_t clim,
atm_t atm 
)

Simulate exponential decay processes for atmospheric particles.

This function simulates decay processes for atmospheric particles based on their mass or volume mixing ratio. It loops over each particle and calculates the decay rate using weighting factors for tropospheric and stratospheric lifetimes. Exponential decay is then calculated, and the mass or volume mixing ratio of particles is updated accordingly. Loss rates can also be calculated and updated based on the decay process.

The function checks for quantity flags to ensure that mass or volume mixing ratio data is available. It then calculates the weighting factor based on the particle's location in the atmosphere and sets the lifetime accordingly. Exponential decay is calculated using the time step and the lifetime, and the particle's mass or volume mixing ratio is updated. Loss rates can also be updated based on the decay process.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climate data structure containing atmospheric data.
atmPointer to the atmospheric data structure containing particle information.
Author
Lars Hoffmann

Definition at line 4227 of file mptrac.c.

4231 {
4232
4233 /* Set timer... */
4234 SELECT_TIMER("MODULE_DECAY", "PHYSICS");
4235
4236 /* Check quantity flags... */
4237 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4238 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4239
4240 /* Loop over particles... */
4241 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
4242
4243 /* Get weighting factor... */
4244 const double w = tropo_weight(ctl, clim, atm, ip);
4245
4246 /* Set lifetime... */
4247 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
4248
4249 /* Calculate exponential decay... */
4250 const double aux = exp(-cache->dt[ip] / tdec);
4251 if (ctl->qnt_m >= 0) {
4252 if (ctl->qnt_mloss_decay >= 0)
4253 atm->q[ctl->qnt_mloss_decay][ip]
4254 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4255 atm->q[ctl->qnt_m][ip] *= aux;
4256 if (ctl->qnt_loss_rate >= 0)
4257 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
4258 }
4259 if (ctl->qnt_vmr >= 0)
4260 atm->q[ctl->qnt_vmr][ip] *= aux;
4261 }
4262}
double tropo_weight(const ctl_t *ctl, const clim_t *clim, const atm_t *atm, const int ip)
Computes a weighting factor based on tropopause pressure.
Definition: mptrac.c:12776
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2683
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2680
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:3128
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:3125
Here is the call graph for this function:

◆ module_diff_meso()

void module_diff_meso ( const ctl_t ctl,
cache_t cache,
const met_t met0,
const met_t met1,
atm_t atm 
)

Simulate mesoscale diffusion for atmospheric particles.

This function simulates mesoscale diffusion for atmospheric particles, including horizontal and vertical wind fluctuations. It calculates standard deviations of local wind data and temporal correlations for mesoscale fluctuations. Mesoscale wind fluctuations are then calculated based on the provided random numbers and turbulence parameters. The particle positions are updated accordingly.

The function loops over each particle and calculates indices for interpolation of wind data. It then computes standard deviations of local wind data and temporal correlations for mesoscale fluctuations. Based on the turbulence parameters and provided random numbers, it calculates horizontal and vertical mesoscale wind fluctuations. Finally, it updates the particle positions based on the calculated wind fluctuations.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the meteorological data structure at the current time step.
met1Pointer to the meteorological data structure at the next time step.
atmPointer to the atmospheric data structure containing particle information.
Note
Control parameters TURB_MESOX and TURB_MESOZ define the subgrid-scale variability as a fraction of the grid-scale variance. Stohl et al. (2005) recommend a default value of 0.16 for both parameters, providing a standard approach for turbulence representation. However, recent findings by Bakels et al. (2024) suggest disabling this approach to improve model accuracy under certain conditions. It is advised to evaluate the applicability of these recommendations based on the specific simulation context and objectives.
Author
Lars Hoffmann

Definition at line 4266 of file mptrac.c.

4271 {
4272
4273 /* Set timer... */
4274 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS");
4275
4276 /* Create random numbers... */
4277 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4278
4279 /* Loop over particles... */
4280 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4281
4282 /* Get indices... */
4283 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
4284 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
4285 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
4286
4287 /* Get standard deviations of local wind data... */
4288 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
4289 for (int i = 0; i < 2; i++)
4290 for (int j = 0; j < 2; j++)
4291 for (int k = 0; k < 2; k++) {
4292 umean += met0->u[ix + i][iy + j][iz + k];
4293 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
4294 vmean += met0->v[ix + i][iy + j][iz + k];
4295 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
4296 wmean += met0->w[ix + i][iy + j][iz + k];
4297 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
4298
4299 umean += met1->u[ix + i][iy + j][iz + k];
4300 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
4301 vmean += met1->v[ix + i][iy + j][iz + k];
4302 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
4303 wmean += met1->w[ix + i][iy + j][iz + k];
4304 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
4305 }
4306 usig = usig / 16.f - SQR(umean / 16.f);
4307 usig = (usig > 0 ? sqrtf(usig) : 0);
4308 vsig = vsig / 16.f - SQR(vmean / 16.f);
4309 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
4310 wsig = wsig / 16.f - SQR(wmean / 16.f);
4311 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
4312
4313 /* Set temporal correlations for mesoscale fluctuations... */
4314 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
4315 const double r2 = sqrt(1 - r * r);
4316
4317 /* Calculate horizontal mesoscale wind fluctuations... */
4318 if (ctl->turb_mesox > 0) {
4319 cache->uvwp[ip][0] =
4320 (float) (r * cache->uvwp[ip][0] +
4321 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
4322 atm->lon[ip] +=
4323 DX2COORD(met0, cache->uvwp[ip][0] * cache->dt[ip], atm->lat[ip]);
4324
4325 cache->uvwp[ip][1] =
4326 (float) (r * cache->uvwp[ip][1] +
4327 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
4328 atm->lat[ip] += DY2COORD(met0, cache->uvwp[ip][1] * cache->dt[ip]);
4329 }
4330
4331 /* Calculate vertical mesoscale wind fluctuations... */
4332 if (ctl->turb_mesoz > 0) {
4333 cache->uvwp[ip][2] =
4334 (float) (r * cache->uvwp[ip][2] +
4335 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
4336 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
4337 }
4338 }
4339}
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3635
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:3062
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2843
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:3059
Here is the call graph for this function:

◆ module_diff_pbl()

void module_diff_pbl ( const ctl_t ctl,
cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Computes particle diffusion within the planetary boundary layer (PBL).

This function handles the effects of turbulence on particles within the PBL. It calculates turbulent velocity variances, Lagrangian timescales, and updates particle positions and perturbations based on random fluctuations and boundary layer physics. This module adapts the approach of Ryall and Maryon (1998) and Stohl et al. (2005).

Parameters
ctlPointer to the control structure containing model settings.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the meteorological data structure for the current timestep.
met1Pointer to the meteorological data structure for the next timestep.
atmPointer to the atmospheric data structure containing particle states.

The function:

  • Allocates memory for random numbers and generates them using module_rng.
  • Loops over all particles to compute their behavior within the boundary layer.
  • Handles both stable/neutral and unstable conditions based on the surface sensible heat flux.
  • Calculates turbulent velocity variances (sig_u, sig_w), their vertical derivatives, and Lagrangian timescales (tau_u, tau_w).
  • Updates particle velocity perturbations and positions using turbulent diffusion equations.

The function uses OpenACC directives for GPU acceleration.

Note
The function handles edge cases like zero diffusivity and imposes minimum limits on calculated values to ensure stability.
Warning
Ensure that all input pointers are properly initialized and accessible before calling this function.
Author
Lars Hoffmann

Definition at line 4343 of file mptrac.c.

4348 {
4349
4350 /* Set timer... */
4351 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS");
4352
4353 /* Create random numbers... */
4354 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4355
4356 /* Loop over particles... */
4357 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4358
4359 double pbl, ps, dsigw_dz = 0.0, sig_u = 0.0, sig_v = 0.0, sig_w = 0.0;
4360 double tau_u = 0.0, tau_v = 0.0, tau_w = 0.0;
4361
4362 /* Get PBL pressure... */
4364 INTPOL_2D(pbl, 1);
4365
4366 /* Let the background diffusion scheme handle particles above the PBL. */
4367 if (atm->p[ip] < pbl)
4368 continue;
4369
4370 /* Get surface pressure... */
4371 INTPOL_2D(ps, 0);
4372
4373 /* Skip invalid or vanishing PBL layers. */
4374 if (!(ps > 0.0 && pbl > 0.0 && ps > pbl))
4375 continue;
4376
4377 /* Calculate heights [m] above ground.
4378 Z() returns altitude in km, so multiply differences by 1e3. */
4379 const double p = MIN(atm->p[ip], ps);
4380 const double zs = Z(ps);
4381 const double z_raw = 1e3 * (Z(p) - zs);
4382 const double zi = 1e3 * (Z(pbl) - zs);
4383
4384 /* Require a physically meaningful PBL depth. */
4385 if (!(zi > 1.0))
4386 continue;
4387
4388 /* Clamp height to the PBL interval for closure evaluation. */
4389 const double z = CLAMP(z_raw, 0.0, zi);
4390 const double zeta = CLAMP(z / zi, 1e-6, 1.0 - 1e-6);
4391 const double z_m = MAX(z, 1.0);
4392
4393 /* Temporarily use clamped pressure for thermodynamic interpolation.
4394 This avoids inconsistent interpolation if a particle has slipped
4395 below the surface pressure. */
4396 const double p_save = atm->p[ip];
4397 atm->p[ip] = p;
4398
4399 /* Calculate friction velocity... */
4400 double ess, nss, h2o, t;
4401 INTPOL_2D(ess, 0);
4402 INTPOL_2D(nss, 0);
4403 INTPOL_3D(t, 1);
4404 INTPOL_3D(h2o, 0);
4405
4406 /* Restore particle pressure before any continue/update path. */
4407 atm->p[ip] = p_save;
4408
4409 const double tv = TVIRT(t, h2o);
4410 const double thetav = THETAVIRT(p, t, h2o);
4411 const double rho = RHO(p, tv);
4412 const double tau = sqrt(SQR(ess) + SQR(nss));
4413
4414 if (!(rho > 0.0))
4415 continue;
4416
4417 const double ustar = sqrt(MAX(tau / rho, 0.0));
4418 const double ust = MAX(1e-4, ustar);
4419
4420 /* Get surface sensible heat flux.
4421 Sign convention assumed here: unstable surface heating gives shf < 0,
4422 as in the existing implementation. */
4423 double shf;
4424 INTPOL_2D(shf, 1);
4425
4426 /* Estimate Monin-Obukhov length [m] to distinguish
4427 neutral, stable, and unstable cases. */
4428 double ol = 1e12;
4429 if (fabs(shf) > 1e-6)
4430 ol = thetav * rho * CPD * SQR(ust) * ust / (KARMAN * G0 * shf);
4431
4432 /* Neutral conditions... */
4433 if (zi / fabs(ol) < 1.0) {
4434
4435 /* corr has units of seconds, hence the exponential coefficients
4436 have units of s^-1. The derivative d(sig_w)/dz therefore needs
4437 the extra factor 1/ust. */
4438 const double corr = z_m / ust;
4439 const double sigw0 = 1.3 * ust * exp(-2e-4 * corr);
4440
4441 sig_u = MAX(2.0 * ust * exp(-3e-4 * corr), 1e-5);
4442 sig_v = MAX(sigw0, 1e-5);
4443 sig_w = MAX(sigw0, 1e-5);
4444 dsigw_dz = -2e-4 * sigw0 / ust;
4445
4446 tau_u = 0.5 * z_m / sig_w / (1.0 + 1.5e-3 * corr);
4447 tau_v = tau_u;
4448 tau_w = tau_u;
4449 }
4450
4451 /* Unstable conditions... */
4452 else if (ol < 0.0) {
4453
4454 /* Convective velocity scale [m/s]. */
4455 const double wstar_arg = -G0 / thetav * shf / (rho * CPD) * zi;
4456 const double wstar = pow(MAX(wstar_arg, 0.0), 1.0 / 3.0);
4457 double dsigw2_dz = 0.0;
4458
4459 /* Hanna1/FLEXPART turbulent velocity standard deviations [m/s]. */
4460 sig_u = MAX(ust * pow(MAX(12.0 - 0.5 * zi / ol, 0.0), 1.0 / 3.0), 1e-6);
4461 sig_v = sig_u;
4462
4463 if (zeta < 0.03) {
4464 const double arg = MAX(3.0 * zeta - ol / zi, 1e-12);
4465 sig_w = 0.96 * wstar * pow(arg, 1.0 / 3.0);
4466 dsigw2_dz = 1.8432 * SQR(wstar) / zi * pow(arg, -1.0 / 3.0);
4467 } else if (zeta < 0.4) {
4468 const double arg = MAX(3.0 * zeta - ol / zi, 1e-12);
4469 const double s1 = 0.96 * pow(arg, 1.0 / 3.0);
4470 const double s2 = 0.763 * pow(zeta, 0.175);
4471 if (s1 < s2) {
4472 sig_w = wstar * s1;
4473 dsigw2_dz = 1.8432 * SQR(wstar) / zi * pow(arg, -1.0 / 3.0);
4474 } else {
4475 sig_w = wstar * s2;
4476 dsigw2_dz = 0.203759 * SQR(wstar) / zi * pow(zeta, -0.65);
4477 }
4478 } else if (zeta < 0.96) {
4479 sig_w = 0.722 * wstar * pow(1.0 - zeta, 0.207);
4480 dsigw2_dz = -0.215812 * SQR(wstar) / zi * pow(1.0 - zeta, -0.586);
4481 } else {
4482 sig_w = 0.37 * wstar;
4483 dsigw2_dz = 0.0;
4484 }
4485
4486 sig_w = MAX(sig_w, 1e-6);
4487 dsigw_dz = sig_w > 1e-12 ? 0.5 * dsigw2_dz / sig_w : 0.0;
4488
4489 /* Hanna/FLEXPART Lagrangian timescales [s]. */
4490 tau_u = 0.15 * zi / MAX(sig_u, 1e-12);
4491 tau_v = tau_u;
4492
4493 if (z_m < fabs(ol)) {
4494 const double denom = 0.55 - 0.38 * fabs(z_m / ol);
4495 tau_w = 0.1 * z_m / (sig_w * MAX(denom, 0.05));
4496 } else if (zeta < 0.1)
4497 tau_w = 0.59 * z_m / sig_w;
4498 else
4499 tau_w = 0.15 * zi / sig_w * (1.0 - exp(-5.0 * zeta));
4500 }
4501
4502 /* Stable conditions... */
4503 else {
4504
4505 sig_u = MAX(2.0 * ust * (1.0 - zeta), 1e-6);
4506 sig_v = MAX(1.3 * ust * (1.0 - zeta), 1e-6);
4507 sig_w = MAX(1.3 * ust * (1.0 - zeta), 1e-6);
4508 dsigw_dz = -1.3 * ust / zi;
4509
4510 tau_u = 0.15 * zi / sig_u * sqrt(zeta);
4511 tau_v = 0.467 * tau_u;
4512 tau_w = 0.1 * zi / sig_w * pow(zeta, 0.8);
4513 }
4514
4515 /* Apply FLEXPART-consistent lower bounds for timescales. */
4516 tau_u = MAX(tau_u, 10.0);
4517 tau_v = MAX(tau_v, 10.0);
4518 tau_w = MAX(tau_w, 30.0);
4519
4520 /* Skip pathological states. */
4521 if (!(sig_u > 0.0 && sig_v > 0.0
4522 && sig_w > 0.0 && tau_u > 0.0 && tau_v > 0.0 && tau_w > 0.0))
4523 continue;
4524
4525 /* Update horizontal perturbation [m/s]. */
4526 const double dt = cache->dt[ip];
4527 const double dt_abs = fabs(dt);
4528
4529 const double ru = exp(-dt_abs / tau_u);
4530 const double ru2 = sqrt(MAX(0.0, 1.0 - SQR(ru)));
4531 const double rv = exp(-dt_abs / tau_v);
4532 const double rv2 = sqrt(MAX(0.0, 1.0 - SQR(rv)));
4533
4534 cache->uvwp[ip][0]
4535 = (float) (cache->uvwp[ip][0] * ru + sig_u * ru2 * cache->rs[3 * ip]);
4536
4537 cache->uvwp[ip][1]
4538 = (float) (cache->uvwp[ip][1] * rv
4539 + sig_v * rv2 * cache->rs[3 * ip + 1]);
4540
4541 /* Update vertical perturbation [m/s].
4542 The drift term is d(sig_w^2)/dz + sig_w^2/rho * d(rho)/dz.
4543 With exponential scale height H0 [km], dln(rho)/dz ~= -1/(1000 H0). */
4544 const double rw = exp(-dt_abs / tau_w);
4545 const double rw2 = sqrt(MAX(0.0, 1.0 - SQR(rw)));
4546 const double rhoaux = -1.0 / (1e3 * H0);
4547
4548 cache->uvwp[ip][2]
4549 = (float) (cache->uvwp[ip][2] * rw + sig_w * rw2 * cache->rs[3 * ip + 2]
4550 + tau_w * (1.0 - rw)
4551 * (2.0 * sig_w * dsigw_dz + rhoaux * SQR(sig_w)));
4552
4553 /* Calculate new horizontal air parcel position. */
4554 atm->lon[ip] += DX2COORD(met0, cache->uvwp[ip][0] * dt, atm->lat[ip]);
4555 atm->lat[ip] += DY2COORD(met0, cache->uvwp[ip][1] * dt);
4556
4557 /* Calculate new height and reflect robustly at surface and PBL top.
4558 Each boundary reflection reverses the vertical turbulent velocity.
4559 This loop is intentionally simple and explicit: it remains correct
4560 even if a large step crosses multiple boundaries. */
4561 double znew = z + cache->uvwp[ip][2] * dt;
4562
4563 while (znew < 0.0 || znew > zi) {
4564
4565 if (znew < 0.0) {
4566 znew = -znew;
4567 cache->uvwp[ip][2] = -cache->uvwp[ip][2];
4568 }
4569
4570 if (znew > zi) {
4571 znew = 2.0 * zi - znew;
4572 cache->uvwp[ip][2] = -cache->uvwp[ip][2];
4573 }
4574 }
4575
4576 /* Set pressure from reflected geometric height.
4577 This is more consistent than a linearized DZ2DP update for
4578 potentially large turbulent steps. */
4579 atm->p[ip] = P(zs + znew / 1000.0);
4580
4581 /* Enforce exact pressure limits of the local PBL column. */
4582 atm->p[ip] = CLAMP(atm->p[ip], pbl, ps);
4583 }
4584}
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:2198
#define H0
Scale height [km].
Definition: mptrac.h:269
#define KARMAN
Karman's constant.
Definition: mptrac.h:279
#define CLAMP(v, lo, hi)
Clamp a value to a specified range.
Definition: mptrac.h:755
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:2152
Here is the call graph for this function:

◆ module_diff_turb()

void module_diff_turb ( const ctl_t ctl,
cache_t cache,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm 
)

Applies turbulent diffusion processes to atmospheric particles.

This function calculates and applies turbulent diffusion effects, including horizontal and vertical diffusion, as well as vertical mixing in the planetary boundary layer (PBL), to a set of atmospheric particles based on input parameters and environmental conditions.

Parameters
[in]ctlPointer to the control structure containing simulation parameters.
[in,out]cachePointer to the cache structure for temporary data and random numbers.
[in]climPointer to the climate structure containing climatological data.
[in,out]met0Pointer to the meteorological data structure for the initial timestep.
[in,out]met1Pointer to the meteorological data structure for the next timestep.
[in,out]atmPointer to the atmospheric structure containing particle data.

The function performs the following operations:

  • Allocates temporary arrays for random number generation.
  • Generates random numbers for simulating diffusion effects.
  • Loops over atmospheric particles to compute and apply:
    • Horizontal turbulent diffusion, based on prescribed diffusivity values.
    • Vertical turbulent diffusion, using vertical diffusivity values.
  • Cleans up allocated resources after processing.

Turbulent diffusivity parameters are derived from control inputs and weighted based on atmospheric layer influences (PBL, troposphere, stratosphere).

Note
  • Control parameters TURB_DX_PBL, TURB_DX_TROP, TURB_DX_STRAT, TURB_DZ_PBL, TURB_DZ_TROP, and TURB_DZ_STRAT define horizontal and vertical diffusivities (in units of m**2 s**-1) in the PBL, troposphere, and stratosphere, respectively.
  • Control parameter TURB_PBL_SCHEME activates an optional PBL-specific closure scheme. If a PBL scheme is active, the fixed-K module is only applied outside the PBL.
  • Apply the following settings to reproduce Stohl et al. (2005): TURB_DX_PBL = 50 TURB_DX_TROP = 50 TURB_DX_STRAT = 0 TURB_DZ_PBL = 0 TURB_DZ_TROP = 0 TURB_DZ_STRAT = 0.1 TURB_MESOX = 0.16 TURB_MESOZ = 0.16 TURB_PBL_SCHEME = 0
  • Apply the following setting to reproduce Maryon et al. (1991) and Ryall et al. (1998): TURB_DX_PBL = 5300 TURB_DX_TROP = 1325 TURB_DX_STRAT = 1325 TURB_DZ_PBL = 0 TURB_DZ_TROP = 1.5 TURB_DZ_STRAT = 1.5 TURB_MESOX = 0 TURB_MESOZ = 0 TURB_PBL_SCHEME = 1
Author
Lars Hoffmann

Definition at line 4588 of file mptrac.c.

4594 {
4595
4596 /* Set timer... */
4597 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS");
4598
4599 /* Create random numbers... */
4600 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4601
4602 /* Loop over particles... */
4603 PARTICLE_LOOP(0, atm->np, 1,
4604 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4605
4606 /* Get PBL pressure... */
4607 double pbl;
4609 INTPOL_2D(pbl, 1);
4610
4611 /* Let optional PBL closure schemes handle turbulent diffusion inside the PBL. */
4612 if (ctl->turb_pbl_scheme > 0 && atm->p[ip] >= pbl)
4613 continue;
4614
4615 /* Get surface pressure... */
4616 double ps;
4617 INTPOL_2D(ps, 0);
4618
4619 /* Pressure at model top [hPa]. */
4620 const double ptop = met0->p[met0->np - 1];
4621
4622 /* Get weighting factors at current particle position... */
4623 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
4624 const double wtrop = tropo_weight(ctl, clim, atm, ip) * (1.0 - wpbl);
4625 const double wstrat = 1.0 - wpbl - wtrop;
4626
4627 /* Set diffusivities [m2/s]... */
4628 const double Kx =
4629 wpbl * ctl->turb_dx_pbl
4630 + wtrop * ctl->turb_dx_trop + wstrat * ctl->turb_dx_strat;
4631
4632 const double Kz =
4633 wpbl * ctl->turb_dz_pbl
4634 + wtrop * ctl->turb_dz_trop + wstrat * ctl->turb_dz_strat;
4635
4636 /* Set time step... */
4637 const double dt_abs = fabs(cache->dt[ip]);
4638
4639 /* Horizontal turbulent diffusion...
4640 Kx [m2/s], dt [s] => sigma_h [m]. */
4641 if (Kx > 0) {
4642 const double sigma_h = sqrt(2.0 * Kx * dt_abs);
4643
4644 atm->lon[ip] +=
4645 DX2COORD(met0, cache->rs[3 * ip] * sigma_h, atm->lat[ip]);
4646
4647 atm->lat[ip] += DY2COORD(met0, cache->rs[3 * ip + 1] * sigma_h);
4648 }
4649
4650 /* Vertical turbulent diffusion... */
4651 if (Kz > 0) {
4652
4653 /* Random displacement:
4654 Kz [m2/s], dt [s] => sigma_z [m], converted to [km]. */
4655 const double sigma_z = sqrt(2.0 * Kz * dt_abs) * 1e-3;
4656
4657 /* Save current pressure because pbl_weight() and tropo_weight()
4658 use atm->p[ip]. */
4659 const double p_save = atm->p[ip];
4660
4661 /* Estimate dKz/dz by centered finite difference.
4662 eps_km = 0.01 km = 10 m.
4663 Positive z is upward; therefore p_up < p_save and p_dn > p_save. */
4664 const double eps_km = 0.01;
4665 const double p_up = p_save + DZ2DP(eps_km, p_save);
4666 const double p_dn = p_save + DZ2DP(-eps_km, p_save);
4667
4668 /* Kz above... */
4669 atm->p[ip] = MAX(ptop, MIN(ps, p_up));
4670 const double wpbl_up = pbl_weight(ctl, atm, ip, pbl, ps);
4671 const double wtrop_up =
4672 tropo_weight(ctl, clim, atm, ip) * (1.0 - wpbl_up);
4673 const double wstrat_up = 1.0 - wpbl_up - wtrop_up;
4674
4675 const double Kz_up =
4676 wpbl_up * ctl->turb_dz_pbl
4677 + wtrop_up * ctl->turb_dz_trop + wstrat_up * ctl->turb_dz_strat;
4678
4679 /* Kz below... */
4680 atm->p[ip] = MAX(ptop, MIN(ps, p_dn));
4681 const double wpbl_dn = pbl_weight(ctl, atm, ip, pbl, ps);
4682 const double wtrop_dn =
4683 tropo_weight(ctl, clim, atm, ip) * (1.0 - wpbl_dn);
4684 const double wstrat_dn = 1.0 - wpbl_dn - wtrop_dn;
4685
4686 const double Kz_dn =
4687 wpbl_dn * ctl->turb_dz_pbl
4688 + wtrop_dn * ctl->turb_dz_trop + wstrat_dn * ctl->turb_dz_strat;
4689
4690 /* Restore current pressure... */
4691 atm->p[ip] = p_save;
4692
4693 /* Well-mixed drift:
4694 w_drift = dKz/dz + Kz * dlnrho/dz
4695
4696 Units:
4697 dKz_dz [m2/s] / [m] = [m/s]
4698 dlnrho_dz [1/m]
4699 Kz*dlnrho [m2/s] * [1/m] = [m/s]
4700 dz_drift [m/s] * [s] * 1e-3 = [km]
4701
4702 With exponential atmosphere rho ~ exp(-z/H0):
4703 dlnrho/dz = -1 / (1000 * H0)
4704 because H0 is in [km]. */
4705 const double dKz_dz = (Kz_up - Kz_dn) / (2.0 * eps_km * 1e3);
4706 const double dlnrho_dz = -1.0 / (1e3 * H0);
4707 const double w_drift = dKz_dz + Kz * dlnrho_dz;
4708 const double dz_drift = w_drift * dt_abs * 1e-3;
4709
4710 /* Total vertical displacement [km]. */
4711 const double dz_tot = cache->rs[3 * ip + 2] * sigma_z + dz_drift;
4712
4713 /* Update particle pressure... */
4714 double ptrial = p_save + DZ2DP(dz_tot, p_save);
4715
4716 /* Reflect at surface and model top.
4717 The transformation p -> pb^2 / p corresponds to reflection in
4718 logarithmic pressure / approximate height coordinates. Use repeated
4719 reflection for robustness in case a large random step crosses more
4720 than one boundary. */
4721 for (int iter = 0; iter < 10; iter++) {
4722 if (ptrial > ps)
4723 ptrial = ps * ps / ptrial;
4724 else if (ptrial < ptop)
4725 ptrial = ptop * ptop / ptrial;
4726 else
4727 break;
4728 }
4729
4730 /* Final safety clamp in case of an exceptionally large displacement... */
4731 atm->p[ip] = MAX(ptop, MIN(ps, ptrial));
4732 }
4733 }
4734}
double pbl_weight(const ctl_t *ctl, const atm_t *atm, const int ip, const double pbl, const double ps)
Computes a weighting factor based on planetary boundary layer pressure.
Definition: mptrac.c:8383
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:940
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:3053
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:3047
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:3044
int turb_pbl_scheme
PBL turbulence scheme (0=none, 1=closure).
Definition: mptrac.h:3038
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:3041
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:3056
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:3050
Here is the call graph for this function:

◆ module_dry_depo()

void module_dry_depo ( const ctl_t ctl,
const cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Simulate dry deposition of atmospheric particles.

This function simulates the dry deposition of atmospheric particles, including both particulate matter and gases. It calculates the sedimentation velocity for particles based on the atmospheric properties and applies it to determine the loss of mass or volume mixing ratio due to deposition. The function loops over each particle and calculates the loss of mass or volume mixing ratio based on the deposition velocity and time step.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the meteorological data structure at the current time step.
met1Pointer to the meteorological data structure at the next time step.
atmPointer to the atmospheric data structure containing particle information.
Author
Lars Hoffmann

Definition at line 4738 of file mptrac.c.

4743 {
4744
4745 /* Set timer... */
4746 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS");
4747
4748 /* Check quantity flags... */
4749 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4750 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4751
4752 /* Loop over particles... */
4753 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4754
4755 /* Get surface pressure... */
4756 double ps;
4758 INTPOL_2D(ps, 1);
4759
4760 /* Check whether particle is above the surface layer... */
4761 if (atm->p[ip] < ps - ctl->dry_depo_dp)
4762 continue;
4763
4764 /* Set depth of surface layer... */
4765 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
4766
4767 /* Calculate sedimentation velocity for particles... */
4768 double v_dep;
4769 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
4770
4771 /* Get temperature... */
4772 double t;
4773 INTPOL_3D(t, 1);
4774
4775 /* Set deposition velocity... */
4776 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4777 atm->q[ctl->qnt_rhop][ip]);
4778 }
4779
4780 /* Use explicit sedimentation velocity for gases... */
4781 else
4782 v_dep = ctl->dry_depo_vdep;
4783
4784 /* Calculate loss of mass based on deposition velocity... */
4785 const double aux = exp(-cache->dt[ip] * v_dep / dz);
4786 if (ctl->qnt_m >= 0) {
4787 if (ctl->qnt_mloss_dry >= 0)
4788 atm->q[ctl->qnt_mloss_dry][ip]
4789 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4790 atm->q[ctl->qnt_m][ip] *= aux;
4791 if (ctl->qnt_loss_rate >= 0)
4792 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
4793 }
4794 if (ctl->qnt_vmr >= 0)
4795 atm->q[ctl->qnt_vmr][ip] *= aux;
4796 }
4797}
double sedi(const double p, const double T, const double rp, const double rhop)
Calculates the sedimentation velocity of a particle in air.
Definition: mptrac.c:12534
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2533
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2530
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:3287
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2677
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:3290
Here is the call graph for this function:

◆ module_h2o2_chem()

void module_h2o2_chem ( const ctl_t ctl,
const cache_t cache,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm 
)

Perform chemical reactions involving H2O2 within cloud particles.

This function simulates chemical reactions involving hydrogen peroxide (H2O2) within cloud particles. It calculates the change in H2O2 concentration over time due to chemical reactions. The reaction rates are determined based on temperature and cloud properties such as liquid water content.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climatological data structure.
met0Pointer to the first meteorological data structure.
met1Pointer to the second meteorological data structure.
atmPointer to the atmospheric data structure containing particle information.
Note
The function assumes that the necessary control structure (ctl), climatological data structure (clim), meteorological data structures (met0, met1), and atmospheric data structure (atm) have been initialized and are accessible.
Chemical reactions involving H2O2 are simulated for particles within clouds, as indicated by a positive liquid water content (LWC).
The function calculates reaction rates based on temperature and cloud properties, including the liquid water content (LWC) and the concentration of SO2.
The exponential decay of H2O2 concentration due to chemical reactions is calculated using the reaction rate coefficient and the time step (dt) for each particle.
If the particle has a quantity flag for either mass (ctl->qnt_m) or volume mixing ratio (ctl->qnt_vmr), the function updates the quantity based on the exponential decay.
If the particle has a loss rate quantity flag (ctl->qnt_loss_rate), the function accumulates the reaction rate coefficient to quantify the loss rate.
Author
Mingzhao Liu

Definition at line 4801 of file mptrac.c.

4807 {
4808
4809 if (ctl->met_coord_type != 0)
4810 ERRMSG("Only lat/lon grid supported");
4811
4812 /* Set timer... */
4813 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS");
4814
4815 /* Check quantity flags... */
4816 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4817 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4818
4819 /* Parameter of SO2 correction... */
4820 const double low = pow(1. / SO2_CORR_A, 1. / SO2_CORR_B);
4821
4822 /* Loop over particles... */
4823 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4824
4825 /* Check whether particle is inside cloud... */
4826 double lwc, rwc;
4828 INTPOL_3D(lwc, 1);
4829 INTPOL_3D(rwc, 0);
4830 if (!(lwc > 0 || rwc > 0))
4831 continue;
4832
4833 /* Get temperature... */
4834 double t;
4835 INTPOL_3D(t, 0);
4836
4837 /* Get molecular density... */
4838 const double M = MOLEC_DENS(atm->p[ip], t);
4839
4840 /* Reaction rate (Berglen et al., 2004)... */
4841 const double k = H2O2_SO2_RATE_REF * exp(-H2O2_SO2_RATE_TEMP / RI * (1. / t - 1. / CHEM_REF_TEMP)); /* Maass (1999), M^(-2) */
4842
4843 /* Henry constant of SO2... */
4844 const double H_SO2 =
4846 * (1. / t - 1. / CHEM_REF_TEMP)) * RI * t;
4847 const double K_1S = SO2_DISS_K1_REF * exp(SO2_DISS_K1_TEMP * (1. / t - 1. / CHEM_REF_TEMP)); /* unit: mol/L */
4848
4849 /* Henry constant of H2O2... */
4850 const double H_h2o2 =
4852 * (1. / t - 1. / CHEM_REF_TEMP)) * RI * t;
4853
4854 /* Correction factor for high SO2 concentration
4855 (if qnt_Cx is defined, the correction is switched on)... */
4856 double cor = 1.0;
4857 if (ctl->qnt_Cx >= 0)
4858 cor = atm->q[ctl->qnt_Cx][ip] >
4859 low ? SO2_CORR_A * pow(atm->q[ctl->qnt_Cx][ip], SO2_CORR_B) : 1;
4860
4861 const double h2o2 = H_h2o2
4862 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
4863 * M * cor * 1000. / AVO; /* unit: mol/L */
4864
4865 /* Volume water content in cloud [m^3 m^(-3)]... */
4866 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
4867 const double CWC = (lwc + rwc) * rho_air / 1e3;
4868
4869 /* Calculate exponential decay (Rolph et al., 1992)... */
4870 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
4871 const double aux = exp(-cache->dt[ip] * rate_coef);
4872 if (ctl->qnt_m >= 0) {
4873 if (ctl->qnt_mloss_h2o2 >= 0)
4874 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
4875 atm->q[ctl->qnt_m][ip] *= aux;
4876 if (ctl->qnt_loss_rate >= 0)
4877 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4878 }
4879 if (ctl->qnt_vmr >= 0)
4880 atm->q[ctl->qnt_vmr][ip] *= aux;
4881 }
4882}
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:249
#define SO2_CORR_B
Exponent of the high-SO2 correction [1].
Definition: mptrac.h:384
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1493
#define SO2_DISS_K1_REF
First SO2 dissociation constant at CHEM_REF_TEMP [mol/L].
Definition: mptrac.h:429
#define SO2_DISS_K1_TEMP
Temperature dependence of the first SO2 dissociation constant [K].
Definition: mptrac.h:434
#define H2O2_HENRY_TEMP
Temperature dependence of the H2O2 Henry constant [K].
Definition: mptrac.h:374
#define SO2_CORR_A
Scale factor of the high-SO2 correction [1].
Definition: mptrac.h:379
#define H2O2_SO2_RATE_REF
Reference rate for aqueous H2O2-SO2 chemistry [L^2/(mol^2 s)].
Definition: mptrac.h:349
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:319
#define H2O2_SO2_RATE_TEMP
Temperature parameter for the aqueous H2O2-SO2 rate [K].
Definition: mptrac.h:354
#define H2O2_HENRY_REF
Henry constant of H2O2 at CHEM_REF_TEMP [mol/(L atm)].
Definition: mptrac.h:369
#define CHEM_REF_TEMP
Reference temperature for chemical equilibrium constants [K].
Definition: mptrac.h:344
#define SO2_HENRY_REF
Henry constant of SO2 at CHEM_REF_TEMP [mol/(L atm)].
Definition: mptrac.h:359
#define SO2_HENRY_TEMP
Temperature dependence of the SO2 Henry constant [K].
Definition: mptrac.h:364
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2668
Here is the call graph for this function:

◆ module_isosurf_init()

void module_isosurf_init ( const ctl_t ctl,
cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Initialize the isosurface module based on atmospheric data.

This function initializes the isosurface module based on the atmospheric data provided. It calculates the necessary variables required for generating the isosurface, such as pressure, density, or potential temperature. Additionally, it can read balloon pressure data from a file if specified in the control structure. The initialized data is stored in the cache for later use.

Parameters
ctlPointer to the control structure containing simulation parameters.
met0Pointer to the meteorological data structure at the current time step.
met1Pointer to the meteorological data structure at the next time step.
atmPointer to the atmospheric data structure containing particle information.
cachePointer to the cache structure for storing initialized data.
Author
Lars Hoffmann

Definition at line 4886 of file mptrac.c.

4891 {
4892
4893 double t;
4894
4895 /* Set timer... */
4896 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS");
4897
4898 /* Save pressure... */
4899 if (ctl->isosurf == 1) {
4900 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
4901 cache->iso_var[ip] = atm->p[ip];
4902 }
4903 }
4904
4905 /* Save density... */
4906 else if (ctl->isosurf == 2) {
4907 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4909 INTPOL_3D(t, 1);
4910 cache->iso_var[ip] = atm->p[ip] / t;
4911 }
4912 }
4913
4914 /* Save potential temperature... */
4915 else if (ctl->isosurf == 3) {
4916 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4918 INTPOL_3D(t, 1);
4919 cache->iso_var[ip] = THETA(atm->p[ip], t);
4920 }
4921 }
4922
4923 /* Read balloon pressure data... */
4924 else if (ctl->isosurf == 4) {
4925
4926 /* Write info... */
4927 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
4928
4929 /* Open file... */
4930 FILE *in;
4931 if (!(in = fopen(ctl->balloon, "r")))
4932 ERRMSG("Cannot open file!");
4933
4934 /* Read pressure time series... */
4935 char line[LEN];
4936 while (fgets(line, LEN, in))
4937 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
4938 &(cache->iso_ps[cache->iso_n])) == 2)
4939 if ((++cache->iso_n) > NP)
4940 ERRMSG("Too many data points!");
4941
4942 /* Check number of points... */
4943 if (cache->iso_n < 1)
4944 ERRMSG("Could not read any data!");
4945
4946 /* Close file... */
4947 fclose(in);
4948
4949 /* Update of cache data on device... */
4950 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4951 }
4952}
void mptrac_update_device(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
Updates device memory for specified data structures.
Definition: mptrac.c:8030
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:2123
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:568
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3629
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3632
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3626
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3623
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:3022
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:3019
Here is the call graph for this function:

◆ module_isosurf()

void module_isosurf ( const ctl_t ctl,
const cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Apply the isosurface module to adjust atmospheric properties.

This function applies the isosurface module to adjust atmospheric properties based on the initialized data stored in the cache. It interpolates and restores atmospheric pressure, density, or potential temperature according to the specified isosurface mode in the control structure.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the meteorological data structure at the current time step.
met1Pointer to the meteorological data structure at the next time step.
atmPointer to the atmospheric data structure containing particle information.
Author
Lars Hoffmann

Definition at line 4956 of file mptrac.c.

4961 {
4962
4963 /* Set timer... */
4964 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS");
4965
4966 /* Loop over particles... */
4967 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4968
4969 /* Init... */
4970 double t;
4972
4973 /* Restore pressure... */
4974 if (ctl->isosurf == 1)
4975 atm->p[ip] = cache->iso_var[ip];
4976
4977 /* Restore density... */
4978 else if (ctl->isosurf == 2) {
4979 INTPOL_3D(t, 1);
4980 atm->p[ip] = cache->iso_var[ip] * t;
4981 }
4982
4983 /* Restore potential temperature... */
4984 else if (ctl->isosurf == 3) {
4985 INTPOL_3D(t, 1);
4986 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / KAPPA);
4987 }
4988
4989 /* Interpolate pressure... */
4990 else if (ctl->isosurf == 4) {
4991 if (atm->time[ip] <= cache->iso_ts[0])
4992 atm->p[ip] = cache->iso_ps[0];
4993 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
4994 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
4995 else {
4996 const int idx =
4997 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
4998 atm->p[ip] =
4999 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
5000 cache->iso_ps[idx + 1], atm->time[ip]);
5001 }
5002 }
5003 }
5004}
#define KAPPA
Exponent used for potential-temperature calculations [1].
Definition: mptrac.h:324
Here is the call graph for this function:

◆ module_meteo()

void module_meteo ( const ctl_t ctl,
const cache_t cache,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm 
)

Update atmospheric properties using meteorological data.

This function updates atmospheric properties based on meteorological data interpolated between two time steps. It calculates various atmospheric quantities such as pressure, temperature, wind speed, humidity, etc., and updates the corresponding fields in the atmospheric data structure.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climate data structure containing climatological data.
met0Pointer to the meteorological data structure at the current time step.
met1Pointer to the meteorological data structure at the next time step.
atmPointer to the atmospheric data structure containing particle information.
Author
Lars Hoffmann

Definition at line 5062 of file mptrac.c.

5068 {
5069
5070 /* Set timer... */
5071 SELECT_TIMER("MODULE_METEO", "PHYSICS");
5072
5073 /* Check quantity flags... */
5074 if (ctl->qnt_tsts >= 0)
5075 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
5076 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
5077
5078 /* Loop over particles... */
5079 PARTICLE_LOOP(0, atm->np, 0,
5080 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5081
5082 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
5083 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
5084 o3, lwc, rwc, iwc, swc, cc, z, zt, eta_d = 0, wdot = 0;
5085
5086 /* Interpolate meteo data... */
5088 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
5089
5090 /* Diagnose eta coordinate on native model levels... */
5091 if (ctl->qnt_eta_d >= 0)
5092 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
5093 met1, met1->pl, met1->zetal,
5094 atm->time[ip], atm->p[ip], atm->lon[ip],
5095 atm->lat[ip], &eta_d, ci, cw, 1);
5096
5097 /* Interpolate vertical velocity on native model levels... */
5098 if ((ctl->advect_vert_coord == 1 && ctl->qnt_zeta_dot >= 0)
5099 || (ctl->advect_vert_coord == 3 && ctl->qnt_eta_dot >= 0))
5100 intpol_met_4d_zeta(met0, met0->pl, met0->zeta_dotl,
5101 met1, met1->pl, met1->zeta_dotl,
5102 atm->time[ip], atm->p[ip], atm->lon[ip],
5103 atm->lat[ip], &wdot, ci, cw, 1);
5104
5105 /* Set quantities... */
5106 SET_ATM(qnt_ps, ps);
5107 SET_ATM(qnt_ts, ts);
5108 SET_ATM(qnt_zs, zs);
5109 SET_ATM(qnt_us, us);
5110 SET_ATM(qnt_vs, vs);
5111 SET_ATM(qnt_ess, ess);
5112 SET_ATM(qnt_nss, nss);
5113 SET_ATM(qnt_shf, shf);
5114 SET_ATM(qnt_lsm, lsm);
5115 SET_ATM(qnt_sst, sst);
5116 SET_ATM(qnt_pbl, pbl);
5117 SET_ATM(qnt_pt, pt);
5118 SET_ATM(qnt_tt, tt);
5119 SET_ATM(qnt_zt, zt);
5120 SET_ATM(qnt_h2ot, h2ot);
5121 SET_ATM(qnt_zg, z);
5122 SET_ATM(qnt_p, atm->p[ip]);
5123 SET_ATM(qnt_t, t);
5124 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
5125 SET_ATM(qnt_u, u);
5126 SET_ATM(qnt_v, v);
5127 SET_ATM(qnt_w, w);
5128 SET_ATM(qnt_h2o, h2o);
5129 SET_ATM(qnt_o3, o3);
5130 SET_ATM(qnt_lwc, lwc);
5131 SET_ATM(qnt_rwc, rwc);
5132 SET_ATM(qnt_iwc, iwc);
5133 SET_ATM(qnt_swc, swc);
5134 SET_ATM(qnt_cc, cc);
5135 SET_ATM(qnt_pct, pct);
5136 SET_ATM(qnt_pcb, pcb);
5137 SET_ATM(qnt_cl, cl);
5138 SET_ATM(qnt_plcl, plcl);
5139 SET_ATM(qnt_plfc, plfc);
5140 SET_ATM(qnt_pel, pel);
5141 SET_ATM(qnt_cape, cape);
5142 SET_ATM(qnt_cin, cin);
5143 SET_ATM(qnt_o3c, o3c);
5144 const double lat_ref =
5145 ctl->met_coord_type == 0 ? atm->lat[ip] : ctl->met_utm_ref_lat;
5146 SET_ATM(qnt_hno3,
5147 clim_zm(&clim->hno3, atm->time[ip], lat_ref, atm->p[ip]));
5148 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
5149 atm->lon[ip], atm->lat[ip], atm->p[ip]));
5150 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
5151 lat_ref, atm->p[ip]));
5152 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip], lat_ref, atm->p[ip]));
5153 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip], lat_ref, atm->p[ip]));
5154 SET_ATM(qnt_vh, sqrt(u * u + v * v));
5155 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
5156 SET_ATM(qnt_psat, PSAT(t));
5157 SET_ATM(qnt_psice, PSICE(t));
5158 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
5159 SET_ATM(qnt_sh, SH(h2o));
5160 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
5161 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
5162 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
5163 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
5164 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
5165 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
5166 SET_ATM(qnt_eta_d, eta_d);
5167 if (ctl->advect_vert_coord == 1) {
5168 SET_ATM(qnt_zeta_dot, wdot);
5169 } else if (ctl->advect_vert_coord == 3) {
5170 SET_ATM(qnt_eta_dot, wdot);
5171 }
5172 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
5173 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
5174 SET_ATM(qnt_pv, pv);
5175 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
5176 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
5177 SET_ATM(qnt_tnat,
5178 nat_temperature(atm->p[ip], h2o,
5179 clim_zm(&clim->hno3, atm->time[ip],
5180 atm->lat[ip], atm->p[ip])));
5181 SET_ATM(qnt_tsts,
5182 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
5183 }
5184}
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:8359
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:3324
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1858
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1831
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:2099
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1935
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:1277
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1905
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:2074
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1807
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3808
int qnt_eta_d
Quantity array index for diagnosed eta vertical coordinate.
Definition: mptrac.h:2719
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2749
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2722
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2743
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2713
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2746
Here is the call graph for this function:

◆ module_mixing()

void module_mixing ( const ctl_t ctl,
const clim_t clim,
atm_t atm,
const double  t 
)

Update atmospheric properties through interparcel mixing.

This function updates atmospheric properties by performing interparcel mixing based on the given meteorological and climatological data. It calculates the indices of grid boxes and performs mixing for various quantities such as mass, volume mixing ratio, and other chemical species concentrations.

Parameters
ctlPointer to the control structure containing simulation parameters.
climPointer to the climate data structure containing climatological data.
atmPointer to the atmospheric data structure containing particle information.
tTime at which mixing is performed.
Author
Mingzhao Liu
Lars Hoffmann

Definition at line 5188 of file mptrac.c.

5192 {
5193
5194 /* Set timer... */
5195 SELECT_TIMER("MODULE_MIXING", "PHYSICS");
5196
5197 /* Allocate... */
5198 const int np = atm->np;
5199 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
5200 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
5201 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
5202
5203 /* Set grid box size... */
5204 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
5205 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
5206 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
5207
5208 /* Set time interval... */
5209 const double t0 = t - 0.5 * ctl->dt_mod;
5210 const double t1 = t + 0.5 * ctl->dt_mod;
5211
5212 /* Get indices... */
5213#ifdef _OPENACC
5214#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
5215#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
5216#pragma acc parallel loop independent gang vector
5217#else
5218#pragma omp parallel for default(shared)
5219#endif
5220 for (int ip = 0; ip < np; ip++) {
5221 const double zpart = Z(atm->p[ip]);
5222 if (atm->time[ip] < t0 || atm->time[ip] > t1
5223 || atm->lon[ip] < ctl->mixing_lon0
5224 || atm->lon[ip] >= ctl->mixing_lon1
5225 || atm->lat[ip] < ctl->mixing_lat0
5226 || atm->lat[ip] >= ctl->mixing_lat1
5227 || zpart < ctl->mixing_z0 || zpart >= ctl->mixing_z1) {
5228 izs[ip] = -1;
5229 continue;
5230 }
5231 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
5232 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
5233 izs[ip] = (int) ((zpart - ctl->mixing_z0) / dz);
5234 if (ixs[ip] >= ctl->mixing_nx || iys[ip] >= ctl->mixing_ny
5235 || izs[ip] >= ctl->mixing_nz)
5236 izs[ip] = -1;
5237 }
5238
5239 /* Calculate interparcel mixing... */
5240 const int use_ensemble = (ctl->nens > 0);
5241
5242 const int quantities[] = {
5243 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
5244 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
5245 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
5246 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
5247 ctl->qnt_Csf6, ctl->qnt_aoa, ctl->qnt_Arn222, ctl->qnt_Apb210,
5248 ctl->qnt_Abe7, ctl->qnt_Acs137, ctl->qnt_Ai131, ctl->qnt_Axe133
5249 };
5250 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
5251
5252 for (int i = 0; i < n_qnt; i++)
5253 if (quantities[i] >= 0)
5254 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
5255 use_ensemble);
5256
5257 /* Free... */
5258#ifdef _OPENACC
5259#pragma acc exit data delete(ixs,iys,izs)
5260#endif
5261 free(ixs);
5262 free(iys);
5263 free(izs);
5264}
void module_mixing_help(const ctl_t *ctl, const clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, const int qnt_idx, const int use_ensemble)
Perform subgrid-scale interparcel mixing of a given quantity.
Definition: mptrac.c:5268
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2764
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:3185
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:3182
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2776
int qnt_Acs137
Quantity array index for radioactive activity of Cs-137.
Definition: mptrac.h:2809
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:3179
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2761
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:3194
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2767
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:3197
int qnt_Ai131
Quantity array index for radioactive activity of I-131.
Definition: mptrac.h:2812
int qnt_Apb210
Quantity array index for radioactive activity of Pb-210.
Definition: mptrac.h:2803
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2770
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:3176
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:3188
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:3200
int qnt_Axe133
Quantity array index for radioactive activity of Xe-133.
Definition: mptrac.h:2815
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2779
int qnt_Abe7
Quantity array index for radioactive activity of Be-7.
Definition: mptrac.h:2806
int qnt_Arn222
Quantity array index for radioactive activity of Rn-222.
Definition: mptrac.h:2800
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2773
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:3191
Here is the call graph for this function:

◆ module_mixing_help()

void module_mixing_help ( const ctl_t ctl,
const clim_t clim,
atm_t atm,
const int *  ixs,
const int *  iys,
const int *  izs,
const int  qnt_idx,
const int  use_ensemble 
)

Perform subgrid-scale interparcel mixing of a given quantity.

This function computes the average of a specified quantity within each subgrid box (and optionally for each ensemble member) and applies a mixing adjustment to particle values based on the computed local mean.

The mixing accounts for differences in tropopause and stratosphere mixing via a weighted parameterization. It supports both ensemble and non-ensemble modes using the use_ensemble flag.

Parameters
[in]ctlPointer to control/configuration structure.
[in]climPointer to climatological data structure.
[in,out]atmPointer to atmospheric state (includes particles).
[in]ixsArray of x-grid indices for each particle.
[in]iysArray of y-grid indices for each particle.
[in]izsArray of z-grid indices for each particle (-1 for invalid).
[in]qnt_idxIndex of the quantity in atm->q to be mixed.
[in]use_ensembleFlag indicating whether to use ensemble-aware logic (0 = no, 1 = yes).
Note
Particles with izs[ip] < 0 are excluded from mixing.
Uses OpenACC or OpenMP for parallelism depending on compilation options.
Requires ctl->qnt_ens to be valid if use_ensemble is true.
Author
Mingzhao Liu
Lars Hoffmann

Definition at line 5268 of file mptrac.c.

5276 {
5277
5278 const int np = atm->np;
5279 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
5280 const int nens = use_ensemble ? ctl->nens : 1;
5281 const int total_grid = ngrid * nens;
5282
5283 double *restrict const cmean =
5284 (double *) malloc((size_t) total_grid * sizeof(double));
5285 int *restrict const count =
5286 (int *) malloc((size_t) total_grid * sizeof(int));
5287
5288 /* Init... */
5289#ifdef _OPENACC
5290#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
5291#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
5292#pragma acc parallel loop independent gang vector
5293#else
5294#ifdef __NVCOMPILER
5295#pragma novector
5296#endif
5297#pragma omp parallel for
5298#endif
5299 for (int i = 0; i < total_grid; i++) {
5300 count[i] = 0;
5301 cmean[i] = 0.0;
5302 }
5303
5304 /* Loop over particles... */
5305#ifdef _OPENACC
5306#pragma acc parallel loop independent gang vector
5307#endif
5308 for (int ip = 0; ip < np; ip++)
5309 if (izs[ip] >= 0) {
5310 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5311 const int idx =
5312 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5313 ctl->mixing_nz);
5314#ifdef _OPENACC
5315#pragma acc atomic update
5316#endif
5317 cmean[idx] += atm->q[qnt_idx][ip];
5318#ifdef _OPENACC
5319#pragma acc atomic update
5320#endif
5321 count[idx]++;
5322 }
5323
5324 /* Compute means... */
5325#ifdef _OPENACC
5326#pragma acc parallel loop independent gang vector
5327#else
5328#ifdef __NVCOMPILER
5329#pragma novector
5330#endif
5331#pragma omp parallel for
5332#endif
5333 for (int i = 0; i < total_grid; i++)
5334 if (count[i] > 0)
5335 cmean[i] /= count[i];
5336
5337 /* Interparcel mixing... */
5338#ifdef _OPENACC
5339#pragma acc parallel loop independent gang vector
5340#else
5341#pragma omp parallel for
5342#endif
5343 for (int ip = 0; ip < np; ip++) {
5344 if (izs[ip] >= 0) {
5345 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5346
5347 double mixparam = 1.0;
5348 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
5349 const double w = tropo_weight(ctl, clim, atm, ip);
5350 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
5351 }
5352
5353 const int idx =
5354 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5355 ctl->mixing_nz);
5356 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
5357 }
5358 }
5359
5360 /* Free... */
5361#ifdef _OPENACC
5362#pragma acc exit data delete(cmean,count)
5363#endif
5364 free(cmean);
5365 free(count);
5366}
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:3170
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:3173
Here is the call graph for this function:

◆ module_oh_chem()

void module_oh_chem ( const ctl_t ctl,
const cache_t cache,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm 
)

Perform hydroxyl chemistry calculations for atmospheric particles.

This function calculates the OH chemistry for each atmospheric particle based on the specified reaction mechanism and updates the particle quantities accordingly. The OH chemistry includes bimolecular and termolecular reactions, and the reaction rates are calculated based on the provided climatological data and atmospheric conditions. The function supports both mass and volume mixing ratio quantities for the particles.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climate data structure containing climatological data.
met0Pointer to the first meteorological data structure.
met1Pointer to the second meteorological data structure.
atmPointer to the atmospheric data structure containing particle information.
Note
The function assumes that the necessary meteorological and climatological data structures have been initialized and are accessible via the pointers met0, met1, and clim, respectively.
The reaction rates are calculated based on the provided reaction mechanism and atmospheric conditions, including temperature, pressure, and the concentrations of relevant species.
The function updates the particle quantities based on the calculated reaction rates and the specified time steps. The update can include both mass and volume mixing ratio quantities, as determined by the control structure (ctl).
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 5370 of file mptrac.c.

5376 {
5377
5378 /* Set timer... */
5379 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS");
5380
5381 /* Check quantity flags... */
5382 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5383 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5384
5385 /* Parameter of SO2 correction... */
5386 const double a = 4.71572206e-08;
5387 const double b = -8.28782867e-01;
5388 const double low = pow(1. / a, 1. / b);
5389
5390 /* Loop over particles... */
5391 PARTICLE_LOOP(0, atm->np, 1,
5392 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5393
5394 /* Get temperature... */
5395 double t;
5397 INTPOL_3D(t, 1);
5398
5399 /* Calculate molecular density... */
5400 const double M = MOLEC_DENS(atm->p[ip], t);
5401
5402 /* Use constant reaction rate... */
5403 double k = NAN;
5404 if (ctl->oh_chem_reaction == 1)
5405 k = ctl->oh_chem[0];
5406
5407 /* Calculate bimolecular reaction rate... */
5408 else if (ctl->oh_chem_reaction == 2)
5409 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
5410
5411 /* Calculate termolecular reaction rate... */
5412 if (ctl->oh_chem_reaction == 3) {
5413
5414 /* Calculate rate coefficient for X + OH + M -> XOH + M
5415 (JPL Publication 19-05) ... */
5416 const double k0 =
5417 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
5418 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
5419 const double ki =
5420 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
5421 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
5422 const double c = log10(k0 * M / ki);
5423 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
5424 }
5425
5426 /* Correction factor for high SO2 concentration
5427 (if qnt_Cx is defined, the correction is switched on)... */
5428 double cor = 1;
5429 if (ctl->qnt_Cx >= 0)
5430 cor =
5431 atm->q[ctl->qnt_Cx][ip] >
5432 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
5433
5434 /* Calculate exponential decay... */
5435 const double rate_coef =
5436 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
5437 atm->lat[ip], atm->p[ip]) * M * cor;
5438 const double aux = exp(-cache->dt[ip] * rate_coef);
5439 if (ctl->qnt_m >= 0) {
5440 if (ctl->qnt_mloss_oh >= 0)
5441 atm->q[ctl->qnt_mloss_oh][ip]
5442 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5443 atm->q[ctl->qnt_m][ip] *= aux;
5444 if (ctl->qnt_loss_rate >= 0)
5445 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
5446 }
5447 if (ctl->qnt_vmr >= 0)
5448 atm->q[ctl->qnt_vmr][ip] *= aux;
5449 }
5450}
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:3233
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:3230
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2665
Here is the call graph for this function:

◆ module_position()

void module_position ( const cache_t cache,
met_t met0,
met_t met1,
atm_t atm,
const int  reflect 
)

Update the positions and pressure levels of atmospheric particles.

This function updates the positions and pressure levels of atmospheric particles based on the meteorological data and the specified time step. It loops over each particle in the atmospheric data structure and performs the following operations:

  • Initializes variables required for interpolation.
  • Calculates modulo for longitude and latitude to ensure they remain within valid ranges.
  • Adjusts latitude if it exceeds the range [-90, 90] degrees.
  • Adjusts longitude if it exceeds the range [-180, 180] degrees.
  • Clamps or reflects pressure at the model top and local surface, as selected by reflect.
Parameters
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the first meteorological data structure.
met1Pointer to the second meteorological data structure.
atmPointer to the atmospheric data structure containing particle information.
reflectSelect reflection (1) or clamping (0) at vertical boundaries.
Note
The function initializes a timer to measure the execution time of the position update process.
Position and pressure updates are performed for each particle using linear interpolation.
Longitude and latitude are adjusted to ensure they remain within valid ranges.
Author
Lars Hoffmann

Definition at line 5454 of file mptrac.c.

5459 {
5460
5461 /* Set timer... */
5462 SELECT_TIMER("MODULE_POSITION", "PHYSICS");
5463
5464 /* Loop over particles... */
5465 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
5466
5467 /* Init... */
5468 double ps;
5470
5471 if (met0->coord_type == 0) {
5472 /* Calculate modulo... */
5473 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
5474 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
5475
5476 /* Check latitude... */
5477 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
5478 if (atm->lat[ip] > 90) {
5479 atm->lat[ip] = 180 - atm->lat[ip];
5480 atm->lon[ip] += 180;
5481 }
5482 if (atm->lat[ip] < -90) {
5483 atm->lat[ip] = -180 - atm->lat[ip];
5484 atm->lon[ip] += 180;
5485 }
5486 }
5487
5488 /* Check longitude... */
5489 while (atm->lon[ip] < -180)
5490 atm->lon[ip] += 360;
5491 while (atm->lon[ip] >= 180)
5492 atm->lon[ip] -= 360;
5493 } else {
5494 intpol_check_cartesian(met0->lon, met0->nx, met0->lat, met0->ny,
5495 atm->lon[ip], atm->lat[ip], &atm->lon[ip],
5496 &atm->lat[ip]);
5497 }
5498
5499 /* Check pressure... */
5500 const double ptop = met0->p[met0->np - 1];
5501 if (atm->p[ip] < ptop) {
5502 atm->p[ip] = reflect ? ptop * ptop / atm->p[ip] : ptop;
5503 } else if (atm->p[ip] > 300.) {
5504 INTPOL_2D(ps, 1);
5505 if (atm->p[ip] > ps)
5506 atm->p[ip] = reflect ? ps * ps / atm->p[ip] : ps;
5507 }
5508 }
5509}
Here is the call graph for this function:

◆ module_radio_decay()

void module_radio_decay ( const ctl_t ctl,
const cache_t cache,
atm_t atm 
)

Apply radioactive decay to atmospheric tracer species.

This routine updates the concentrations of radioactive tracers carried by atmospheric particles by applying exponential decay over the current particle timestep. The decay constants are derived from the half-lives of the respective isotopes.

Implemented isotopes:

  • Rn-222
  • Pb-210
  • Be-7
  • Cs-137
  • I-131
  • Xe-133

For each particle, the tracer mixing ratios are reduced according to \( q(t+\Delta t) = q(t) \exp(-\lambda \Delta t) \), where \(\lambda\) is the decay constant and \(\Delta t\) is the particle timestep.

Additionally, the decay of Rn-222 contributes to the production of Pb-210 via a simplified parent–daughter relationship.

The update is performed only if the corresponding tracer index in the control structure is non-negative.

Parameters
[in]ctlControl structure containing tracer indices.
[in]cacheCache structure providing particle timesteps.
[in,out]atmAtmospheric state containing particle tracer fields that are updated in place.
Author
Lars Hoffmann

Definition at line 5513 of file mptrac.c.

5516 {
5517
5518 /* Set timer... */
5519 SELECT_TIMER("MODULE_RADIO_DECAY", "PHYSICS");
5520
5521 /* Set decay constants of radioactive species [s^-1]... */
5522 const double lambda_rn222 = log(2.0) / RADIO_HALF_LIFE_RN222;
5523 const double lambda_pb210 = log(2.0) / RADIO_HALF_LIFE_PB210;
5524 const double lambda_be7 = log(2.0) / RADIO_HALF_LIFE_BE7;
5525 const double lambda_cs137 = log(2.0) / RADIO_HALF_LIFE_CS137;
5526 const double lambda_i131 = log(2.0) / RADIO_HALF_LIFE_I131;
5527 const double lambda_xe133 = log(2.0) / RADIO_HALF_LIFE_XE133;
5528
5529 /* Loop over particles... */
5530 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,atm)") {
5531
5532 /* Set timestep... */
5533 const double dt = cache->dt[ip];
5534
5535 /* Loss for Pb-210... */
5536 if (ctl->qnt_Apb210 >= 0)
5537 atm->q[ctl->qnt_Apb210][ip] *= exp(-dt * lambda_pb210);
5538
5539 /* Loss for Rn-222... */
5540 if (ctl->qnt_Arn222 >= 0) {
5541 const double old = atm->q[ctl->qnt_Arn222][ip];
5542 const double aux = exp(-dt * lambda_rn222);
5543 const double lost = old * (1.0 - aux);
5544 atm->q[ctl->qnt_Arn222][ip] = old * aux;
5545
5546 /* Parent-daughter process for Pb-210... */
5547 if (ctl->qnt_Apb210 >= 0)
5548 atm->q[ctl->qnt_Apb210][ip] += lost * lambda_pb210 / lambda_rn222;
5549 }
5550
5551 /* Loss for Be-7... */
5552 if (ctl->qnt_Abe7 >= 0)
5553 atm->q[ctl->qnt_Abe7][ip] *= exp(-dt * lambda_be7);
5554
5555 /* Loss for Cs-137... */
5556 if (ctl->qnt_Acs137 >= 0)
5557 atm->q[ctl->qnt_Acs137][ip] *= exp(-dt * lambda_cs137);
5558
5559 /* Loss for I-131... */
5560 if (ctl->qnt_Ai131 >= 0)
5561 atm->q[ctl->qnt_Ai131][ip] *= exp(-dt * lambda_i131);
5562
5563 /* Loss for Xe-133... */
5564 if (ctl->qnt_Axe133 >= 0)
5565 atm->q[ctl->qnt_Axe133][ip] *= exp(-dt * lambda_xe133);
5566 }
5567}
#define RADIO_HALF_LIFE_CS137
Half-life of Cs-137 [s].
Definition: mptrac.h:479
#define RADIO_HALF_LIFE_I131
Half-life of I-131 [s].
Definition: mptrac.h:484
#define RADIO_HALF_LIFE_BE7
Half-life of Be-7 [s].
Definition: mptrac.h:474
#define RADIO_HALF_LIFE_RN222
Half-life of Rn-222 [s].
Definition: mptrac.h:464
#define RADIO_HALF_LIFE_PB210
Half-life of Pb-210 [s].
Definition: mptrac.h:469
#define RADIO_HALF_LIFE_XE133
Half-life of Xe-133 [s].
Definition: mptrac.h:489

◆ module_radio_depo()

void module_radio_depo ( const ctl_t ctl,
const cache_t cache,
met_t met0,
met_t met1,
atm_t atm,
depo_t depo 
)

Deposit supported radionuclides from air parcels onto the ground grid.

Applies fixed dry-deposition velocities in the surface layer and precipitation-dependent wet scavenging to Apb210, Abe7, Acs137, and Ai131. Air-parcel activities are reduced exponentially and the removed activity is accumulated in depo. When RADIO_DECAY is enabled, ground inventories are referenced to the simulation start for decay-correct output. Backward or zero-length particle timesteps are ignored.

Note
This module requires a latitude/longitude meteorological grid and is not currently supported with domain decomposition (DD).
Parameters
[in]ctlControl parameters, quantity indices, and deposition grid.
[in]cachePer-particle model timesteps.
[in]met0Meteorological field at the earlier bracketing time.
[in]met1Meteorological field at the later bracketing time.
[in,out]atmAir-parcel positions and activities [Bq].
[in,out]depoCumulative ground inventories [Bq per grid cell].

Definition at line 5571 of file mptrac.c.

5577 {
5578
5579 /* Set timer... */
5580 SELECT_TIMER("MODULE_RADIO_DEPO", "PHYSICS");
5581
5582 /* Decay constants of deposited radionuclides [s^-1]... */
5583 const double lambda_pb210 = log(2.0) / RADIO_HALF_LIFE_PB210;
5584 const double lambda_be7 = log(2.0) / RADIO_HALF_LIFE_BE7;
5585 const double lambda_cs137 = log(2.0) / RADIO_HALF_LIFE_CS137;
5586 const double lambda_i131 = log(2.0) / RADIO_HALF_LIFE_I131;
5587
5588 /* Set horizontal grid increments... */
5589 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
5590 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
5591
5592 /* Loop over particles... */
5593 PARTICLE_LOOP(0, atm->np, 1,
5594 "acc data present(ctl,cache,met0,met1,atm,depo)") {
5595
5596 /* Deposition is only defined for forward integration... */
5597 const double dt = cache->dt[ip];
5598 if (dt <= 0)
5599 continue;
5600
5601 /* Get surface pressure... */
5602 double ps;
5604 INTPOL_2D(ps, 1);
5605
5606 /* Calculate dry deposition rate [s^-1]... */
5607 double dry_pb210 = 0, dry_be7 = 0, dry_cs137 = 0, dry_i131 = 0;
5608 if (atm->p[ip] >= ps - ctl->dry_depo_dp) {
5609 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
5610 if (dz > 0) {
5611 dry_pb210 = RADIO_DRY_VDEP_PB210 / dz;
5612 dry_be7 = RADIO_DRY_VDEP_BE7 / dz;
5613 dry_cs137 = RADIO_DRY_VDEP_CS137 / dz;
5614 dry_i131 = RADIO_DRY_VDEP_I131 / dz;
5615 }
5616 }
5617
5618 /* Calculate wet deposition rate [s^-1]... */
5619 double wet_pb210 = 0, wet_be7 = 0, wet_cs137 = 0, wet_i131 = 0;
5620 double pct;
5621 INTPOL_2D(pct, 1);
5622 if (isfinite(pct) && atm->p[ip] > pct) {
5623 double cl;
5624 INTPOL_2D(cl, 0);
5625 if (cl > 0) {
5626 const double Is =
5627 pow(cl / ctl->wet_depo_pre[0], 1. / ctl->wet_depo_pre[1]);
5628 if (Is >= 0.01) {
5629 double lwc, rwc, iwc, swc, t;
5630 INTPOL_3D(lwc, 1);
5631 INTPOL_3D(rwc, 0);
5632 INTPOL_3D(iwc, 0);
5633 INTPOL_3D(swc, 0);
5634 INTPOL_3D(t, 0);
5635 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
5636 double eta;
5637 if (inside) {
5638 if (t > WET_DEPO_T_LIQUID)
5639 eta = 1;
5640 else if (t <= WET_DEPO_T_ICE)
5641 eta = ctl->wet_depo_ic_ret_ratio;
5642 else
5644 ctl->wet_depo_ic_ret_ratio, t);
5645 } else
5646 eta = (t > WET_DEPO_T_LIQUID_BC ? 1 : ctl->wet_depo_bc_ret_ratio);
5647 wet_pb210 = RADIO_WET_COEFF_PB210 * Is * eta;
5648 wet_be7 = RADIO_WET_COEFF_BE7 * Is * eta;
5649 wet_cs137 = RADIO_WET_COEFF_CS137 * Is * eta;
5650 wet_i131 = RADIO_WET_COEFF_I131 * Is * eta;
5651 }
5652 }
5653 }
5654
5655 /* Get deposition grid index... */
5656 const int ingrid =
5657 (atm->lon[ip] >= ctl->grid_lon0
5658 && atm->lon[ip] < ctl->grid_lon1
5659 && atm->lat[ip] >= ctl->grid_lat0 && atm->lat[ip] < ctl->grid_lat1);
5660 const int ix = ingrid
5661 ? (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon) : 0;
5662 const int iy = ingrid
5663 ? (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat) : 0;
5664 const int idx = (ingrid ? ARRAY_2D(ix, iy, ctl->grid_ny) : 0);
5665 const double tref = atm->time[ip] - ctl->t_start;
5666
5667 /* Deposit Pb-210... */
5668 if (ctl->qnt_Apb210 >= 0) {
5669 const double old = atm->q[ctl->qnt_Apb210][ip];
5670 const double aux = exp(-dt * (dry_pb210 + wet_pb210));
5671 const double lost = old * (1. - aux);
5672 const double deposited = lost
5673 * (ctl->radio_decay ? exp(lambda_pb210 * tref) : 1.0);
5674 atm->q[ctl->qnt_Apb210][ip] = old * aux;
5675 if (ingrid && lost > 0) {
5676#ifdef _OPENACC
5677#pragma acc atomic update
5678#else
5679#pragma omp atomic update
5680#endif
5681 depo->Apb210[idx] += deposited;
5682 }
5683 }
5684
5685 /* Deposit Be-7... */
5686 if (ctl->qnt_Abe7 >= 0) {
5687 const double old = atm->q[ctl->qnt_Abe7][ip];
5688 const double aux = exp(-dt * (dry_be7 + wet_be7));
5689 const double lost = old * (1. - aux);
5690 const double deposited = lost
5691 * (ctl->radio_decay ? exp(lambda_be7 * tref) : 1.0);
5692 atm->q[ctl->qnt_Abe7][ip] = old * aux;
5693 if (ingrid && lost > 0) {
5694#ifdef _OPENACC
5695#pragma acc atomic update
5696#else
5697#pragma omp atomic update
5698#endif
5699 depo->Abe7[idx] += deposited;
5700 }
5701 }
5702
5703 /* Deposit Cs-137... */
5704 if (ctl->qnt_Acs137 >= 0) {
5705 const double old = atm->q[ctl->qnt_Acs137][ip];
5706 const double aux = exp(-dt * (dry_cs137 + wet_cs137));
5707 const double lost = old * (1. - aux);
5708 const double deposited = lost
5709 * (ctl->radio_decay ? exp(lambda_cs137 * tref) : 1.0);
5710 atm->q[ctl->qnt_Acs137][ip] = old * aux;
5711 if (ingrid && lost > 0) {
5712#ifdef _OPENACC
5713#pragma acc atomic update
5714#else
5715#pragma omp atomic update
5716#endif
5717 depo->Acs137[idx] += deposited;
5718 }
5719 }
5720
5721 /* Deposit aerosol-bound I-131... */
5722 if (ctl->qnt_Ai131 >= 0) {
5723 const double old = atm->q[ctl->qnt_Ai131][ip];
5724 const double aux = exp(-dt * (dry_i131 + wet_i131));
5725 const double lost = old * (1. - aux);
5726 const double deposited = lost
5727 * (ctl->radio_decay ? exp(lambda_i131 * tref) : 1.0);
5728 atm->q[ctl->qnt_Ai131][ip] = old * aux;
5729 if (ingrid && lost > 0) {
5730#ifdef _OPENACC
5731#pragma acc atomic update
5732#else
5733#pragma omp atomic update
5734#endif
5735 depo->Ai131[idx] += deposited;
5736 }
5737 }
5738 }
5739}
#define RADIO_DRY_VDEP_I131
Dry deposition velocity of aerosol-bound I-131 [m/s].
Definition: mptrac.h:509
#define RADIO_DRY_VDEP_CS137
Dry deposition velocity of Cs-137 [m/s].
Definition: mptrac.h:504
#define RADIO_DRY_VDEP_PB210
Dry deposition velocity of Pb-210 [m/s].
Definition: mptrac.h:494
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:689
#define WET_DEPO_T_ICE
Lower temperature of the ice-cloud retention transition [K].
Definition: mptrac.h:454
#define RADIO_WET_COEFF_BE7
Wet deposition coefficient of Be-7 [s^-1].
Definition: mptrac.h:519
#define RADIO_WET_COEFF_CS137
Wet deposition coefficient of Cs-137 [s^-1].
Definition: mptrac.h:524
#define RADIO_WET_COEFF_I131
Wet deposition coefficient of aerosol-bound I-131 [s^-1].
Definition: mptrac.h:529
#define RADIO_DRY_VDEP_BE7
Dry deposition velocity of Be-7 [m/s].
Definition: mptrac.h:499
#define WET_DEPO_T_LIQUID
Upper temperature of the ice-cloud retention transition [K].
Definition: mptrac.h:449
#define WET_DEPO_T_LIQUID_BC
Temperature threshold for below-cloud retention [K].
Definition: mptrac.h:459
#define RADIO_WET_COEFF_PB210
Wet deposition coefficient of Pb-210 [s^-1].
Definition: mptrac.h:514
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3432
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3444
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3435
int radio_decay
RADIO_DECAY switch for airborne and deposited activity (0=off, 1=on, default: 0).
Definition: mptrac.h:3251
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3438
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:3257
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3441
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:3284
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:3281
double t_start
Start time of simulation [s].
Definition: mptrac.h:2827
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3447
double Ai131[EX *EY]
Deposited I-131 activity [Bq].
Definition: mptrac.h:3668
double Abe7[EX *EY]
Deposited Be-7 activity [Bq].
Definition: mptrac.h:3662
double Acs137[EX *EY]
Deposited Cs-137 activity [Bq].
Definition: mptrac.h:3665
double Apb210[EX *EY]
Deposited Pb-210 activity [Bq].
Definition: mptrac.h:3659

◆ module_rng_init()

void module_rng_init ( const int  ntask)

Initialize random number generators for parallel tasks.

This function initializes random number generators for parallel tasks using both GSL (GNU Scientific Library) and cuRAND (NVIDIA CUDA Random Number Generation Library) if available. It sets up GSL random number generators for each OpenMP thread and initializes them with unique seeds. For cuRAND, it creates a pseudo-random number generator and sets its seed. The initialization ensures that each task or thread has its own independent random number generator to prevent interference between parallel executions.

Parameters
ntaskThe number of tasks or parallel threads for which random number generators are initialized.
Note
This function must be called before using any random number generation functions to ensure proper initialization of random number generators.
GSL random number generators are initialized for each OpenMP thread, while cuRAND is initialized for the entire task set.
If cuRAND is not available (CURAND macro not defined), the cuRAND initialization section is skipped.
Random number generators are allocated and seeded uniquely for each task or thread to ensure independence and avoid interference between parallel executions.
Author
Lars Hoffmann

Definition at line 5743 of file mptrac.c.

5744 {
5745
5746 /* Initialize GSL random number generators... */
5747 gsl_rng_env_setup();
5748 if (omp_get_max_threads() > NTHREADS)
5749 ERRMSG("Too many threads!");
5750 for (int i = 0; i < NTHREADS; i++) {
5751 rng[i] = gsl_rng_alloc(gsl_rng_default);
5752 gsl_rng_set(rng[i], gsl_rng_default_seed
5753 + (long unsigned) (ntask * NTHREADS + i));
5754 }
5755
5756 /* Initialize cuRAND random number generators... */
5757#ifdef CURAND
5758 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
5759 CURAND_STATUS_SUCCESS)
5760 ERRMSG("Cannot create random number generator!");
5761 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
5762 CURAND_STATUS_SUCCESS)
5763 ERRMSG("Cannot set seed for random number generator!");
5764 if (curandSetStream
5765 (rng_curand,
5766 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
5767 CURAND_STATUS_SUCCESS)
5768 ERRMSG("Cannot set stream for random number generator!");
5769#endif
5770}
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:593

◆ module_rng()

void module_rng ( const ctl_t ctl,
double *  rs,
const size_t  n,
const int  method 
)

Generate random numbers using various methods and distributions.

This function generates random numbers using different methods and distributions based on the specified method and random number generator type. It supports uniform and normal distributions and can utilize GSL, Squares (Widynski, 2022), or cuRAND random number generators.

Parameters
ctlPointer to the control structure containing parameters and settings.
rsPointer to the array where the generated random numbers will be stored.
nThe number of random numbers to generate.
methodThe method for generating random numbers:
  • 0: Uniform distribution
  • 1: Normal distribution
Note
The function selects the appropriate random number generator based on the specified method and the random number generator type defined in the control structure (ctl->rng_type).
For uniform distribution, the generated random numbers are in the range [0, 1).
For normal distribution, the Box-Muller transform is used to generate pairs of random numbers and transform them into a normal distribution.
If cuRAND is not available (CURAND macro not defined), the function returns an error message.
Author
Lars Hoffmann

Definition at line 5774 of file mptrac.c.

5778 {
5779
5780 /* Use GSL random number generators... */
5781 if (ctl->rng_type == 0) {
5782
5783 /* Uniform distribution... */
5784 if (method == 0) {
5785#pragma omp parallel for default(shared)
5786 for (size_t i = 0; i < n; ++i)
5787 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
5788 }
5789
5790 /* Normal distribution... */
5791 else if (method == 1) {
5792#pragma omp parallel for default(shared)
5793 for (size_t i = 0; i < n; ++i)
5794 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
5795 }
5796
5797 /* Update of random numbers on device... */
5798#ifdef _OPENACC
5799 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
5800#pragma acc update device(rs[:n])
5801#endif
5802 }
5803
5804 /* Use Squares random number generator (Widynski, 2022)... */
5805 else if (ctl->rng_type == 1) {
5806
5807 /* Set key (don't change this!)... */
5808 const uint64_t key = 0xc8e4fd154ce32f6d;
5809
5810 /* Uniform distribution... */
5811#ifdef _OPENACC
5812#pragma acc data present(rs)
5813#pragma acc parallel loop independent gang vector
5814#else
5815#pragma omp parallel for default(shared)
5816#endif
5817 for (size_t i = 0; i < n + 1; ++i) {
5818 uint64_t r, t, x, y, z;
5819 y = x = (rng_ctr + i) * key;
5820 z = y + key;
5821 x = x * x + y;
5822 x = (x >> 32) | (x << 32);
5823 x = x * x + z;
5824 x = (x >> 32) | (x << 32);
5825 x = x * x + y;
5826 x = (x >> 32) | (x << 32);
5827 t = x = x * x + z;
5828 x = (x >> 32) | (x << 32);
5829 r = t ^ ((x * x + y) >> 32);
5830 rs[i] = (double) r / (double) UINT64_MAX;
5831 }
5832 rng_ctr += n + 1;
5833
5834 /* Normal distribution... */
5835 if (method == 1) {
5836#ifdef _OPENACC
5837#pragma acc parallel loop independent gang vector
5838#else
5839#pragma omp parallel for default(shared)
5840#endif
5841 for (size_t i = 0; i < n; i += 2) {
5842 const double r = sqrt(-2.0 * log(rs[i]));
5843 const double phi = 2.0 * M_PI * rs[i + 1];
5844 rs[i] = r * cosf((float) phi);
5845 rs[i + 1] = r * sinf((float) phi);
5846 }
5847 }
5848 }
5849
5850 /* Use cuRAND random number generators... */
5851 else if (ctl->rng_type == 2) {
5852#ifdef CURAND
5853#pragma acc host_data use_device(rs)
5854 {
5855
5856 /* Uniform distribution... */
5857 if (method == 0) {
5858 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
5859 CURAND_STATUS_SUCCESS)
5860 ERRMSG("Cannot create random numbers!");
5861 }
5862
5863 /* Normal distribution... */
5864 else if (method == 1) {
5865 if (curandGenerateNormalDouble
5866 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
5867 1.0) != CURAND_STATUS_SUCCESS)
5868 ERRMSG("Cannot create random numbers!");
5869 }
5870 }
5871#else
5872 ERRMSG("MPTRAC was compiled without cuRAND!");
5873#endif
5874 }
5875}
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:3032

◆ module_sedi()

void module_sedi ( const ctl_t ctl,
const cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Simulate sedimentation of particles in the atmosphere.

This function calculates the sedimentation velocity of particles based on atmospheric pressure, temperature, and particle properties such as radius and density. It then updates the pressure of each particle based on the sedimentation velocity and the specified time step.

Parameters
ctlPointer to the control structure containing parameters and settings.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the meteorological data at the current time step.
met1Pointer to the meteorological data at the next time step.
atmPointer to the atmospheric data containing particle information.
Note
The sedimentation velocity is calculated using the sedi function, which takes atmospheric pressure, temperature, particle radius, and particle density as inputs.
The pressure change for each particle is calculated based on the sedimentation velocity and the specified time step using the DZ2DP function.
Author
Lars Hoffmann

Definition at line 5879 of file mptrac.c.

5884 {
5885
5886 /* Set timer... */
5887 SELECT_TIMER("MODULE_SEDI", "PHYSICS")
5888 /* Loop over particles... */
5889 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5890
5891 /* Get temperature... */
5892 double t;
5894 INTPOL_3D(t, 1);
5895
5896 /* Sedimentation velocity... */
5897 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
5898 atm->q[ctl->qnt_rhop][ip]);
5899
5900 /* Calculate pressure change... */
5901 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
5902 }
5903}
Here is the call graph for this function:

◆ module_sort()

void module_sort ( const ctl_t ctl,
const met_t met0,
atm_t atm 
)

Sort particles according to box index.

This function sorts particles within the atmosphere data structure based on their geographical coordinates (longitude and latitude) and pressure level. It allocates temporary arrays to store indices and auxiliary data for sorting, then performs the sorting operation. After sorting, it updates the order of particles in the atmosphere data structure.

Parameters
ctlPointer to the control structure containing parameters and settings.
met0Pointer to the meteorological data at the current time step.
atmPointer to the atmospheric data containing particle information.
Note
The function utilizes the locate_reg and locate_irr functions to determine the appropriate index for sorting particles based on their longitude, latitude, and pressure level.
Particle sorting is performed using either the Thrust library (if compiled with Thrust support) or a custom sorting algorithm. If compiled without Thrust support, an error message is displayed.
After sorting, the function updates the order of particle-related data arrays in the atmosphere data structure to maintain consistency.
Author
Lars Hoffmann

Definition at line 5907 of file mptrac.c.

5910 {
5911
5912 /* Set timer... */
5913 SELECT_TIMER("MODULE_SORT", "PHYSICS");
5914
5915 /* Allocate... */
5916 const int np = atm->np;
5917 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
5918 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
5919 if (a == NULL || p == NULL)
5920 ERRMSG("Out of memory!");
5921
5922#ifdef _OPENACC
5923#pragma acc enter data create(a[0:np],p[0:np])
5924#pragma acc data present(ctl,met0,atm,a,p)
5925#endif
5926
5927 /* Get box index... */
5928#ifdef _OPENACC
5929#pragma acc parallel loop independent gang vector
5930#else
5931#pragma omp parallel for default(shared)
5932#endif
5933 for (int ip = 0; ip < np; ip++) {
5934 a[ip] =
5935 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
5936 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
5937 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
5938 p[ip] = ip;
5939 }
5940
5941 /* Sorting... */
5942#ifdef THRUST
5943#ifdef _OPENACC
5944#pragma acc host_data use_device(a,p)
5945#endif
5946 thrustSortWrapper(a, np, p);
5947#else
5948 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
5949 if (perm_sz == NULL)
5950 ERRMSG("Out of memory!");
5951#ifdef _OPENACC
5952#pragma acc update self(a[0:np])
5953#endif
5954 gsl_sort_index(perm_sz, a, 1, (size_t) np);
5955 for (int ip = 0; ip < np; ++ip)
5956 p[ip] = (int) perm_sz[ip];
5957 free(perm_sz);
5958#ifdef _OPENACC
5959#pragma acc update device(p[0:np])
5960#endif
5961#endif
5962
5963 /* Sort data... */
5964 module_sort_help(atm->time, p, np);
5965 module_sort_help(atm->p, p, np);
5966 module_sort_help(atm->lon, p, np);
5967 module_sort_help(atm->lat, p, np);
5968 for (int iq = 0; iq < ctl->nq; iq++)
5969 module_sort_help(atm->q[iq], p, np);
5970
5971 /* Free... */
5972#ifdef _OPENACC
5973#pragma acc exit data delete(a,p)
5974#endif
5975 free(a);
5976 free(p);
5977}
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:5981
int nq
Number of quantities.
Definition: mptrac.h:2500
Here is the call graph for this function:

◆ module_sort_help()

void module_sort_help ( double *  a,
const int *  p,
const int  np 
)

Reorder an array based on a given permutation.

This function reorders the elements of a given array based on a specified permutation array. It allocates temporary memory to store the reordered elements, performs the reordering operation, and then updates the original array with the reordered elements.

Parameters
aPointer to the array to be reordered.
pPointer to the permutation array defining the order of elements.
npThe number of elements in the array.
Note
The function utilizes temporary memory to store the reordered elements before updating the original array to prevent data loss or corruption.
Reordering is performed based on the permutation array p, which defines the new order of elements in the array a.
Author
Lars Hoffmann

Definition at line 5981 of file mptrac.c.

5984 {
5985
5986 /* Allocate... */
5987 double *restrict const help =
5988 (double *) malloc((size_t) np * sizeof(double));
5989 if (help == NULL)
5990 ERRMSG("Out of memory!");
5991
5992 /* Reordering of array... */
5993#ifdef _OPENACC
5994#pragma acc enter data create(help[0:np])
5995#pragma acc data present(a,p,help)
5996#pragma acc parallel loop independent gang vector
5997#else
5998#pragma omp parallel for default(shared)
5999#endif
6000 for (int ip = 0; ip < np; ip++)
6001 help[ip] = a[p[ip]];
6002#ifdef _OPENACC
6003#pragma acc parallel loop independent gang vector
6004#else
6005#pragma omp parallel for default(shared)
6006#endif
6007 for (int ip = 0; ip < np; ip++)
6008 a[ip] = help[ip];
6009
6010 /* Free... */
6011#ifdef _OPENACC
6012#pragma acc exit data delete(help)
6013#endif
6014 free(help);
6015}

◆ module_timesteps()

void module_timesteps ( const ctl_t ctl,
cache_t cache,
const met_t met0,
atm_t atm,
const double  t 
)

Calculate time steps for air parcels based on specified conditions.

This function calculates the time steps for air parcels based on specified conditions, including the direction of simulation, start and stop times, and a given target time. It adjusts the time step for each air parcel accordingly and checks for horizontal boundary conditions of local meteorological data.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the initial meteorological data structure.
atmPointer to the atmospheric data structure containing air parcel information.
tThe target time for which time steps are calculated.
Note
The function sets the time step for each air parcel based on its current time relative to the start and stop times of the simulation, as well as the specified target time t.
It also checks for horizontal boundaries of local meteorological data and adjusts the time step accordingly if necessary.
Author
Lars Hoffmann

Definition at line 6019 of file mptrac.c.

6024 {
6025
6026 /* Set timer... */
6027 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS");
6028
6029 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
6030 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
6031
6032 const int local =
6033 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
6034
6035 /* Loop over particles... */
6036 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
6037
6038 /* Set time step for each air parcel... */
6039 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
6040 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
6041 && ctl->direction * (atm->time[ip] - t) < 0))
6042 cache->dt[ip] = t - atm->time[ip];
6043 else
6044 cache->dt[ip] = 0.0;
6045
6046 /* Check horizontal boundaries of local meteo data... */
6047#ifndef DD
6048 int dd = 1;
6049#else
6050 int dd = 0;
6051#endif
6052 if (dd) {
6053 if (local && (atm->lon[ip] <= met0->lon[0]
6054 || atm->lon[ip] >= met0->lon[met0->nx - 1]
6055 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
6056 cache->dt[ip] = 0.0;
6057 } else {
6058 if ((int) atm->q[ctl->qnt_current_subdomain][ip] == -1)
6059 cache->dt[ip] = 0;
6060 }
6061 }
6062}
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2824
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2830
int qnt_current_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2818

◆ module_timesteps_init()

void module_timesteps_init ( ctl_t ctl,
const atm_t atm 
)

Initialize start time and time interval for time-stepping.

This function initializes the start time and time interval for time-stepping based on the direction of simulation and the provided atmospheric data. It sets the start time according to the minimum or maximum time in the atmospheric data, depending on the simulation direction. Additionally, it checks the time interval and adjusts the start time accordingly for rounding purposes.

Parameters
ctlPointer to the control structure containing simulation parameters.
atmPointer to the atmospheric data structure containing air parcel information.
Note
The function sets the start time based on the direction of simulation and the minimum or maximum time in the atmospheric data.
It checks the time interval to ensure that there is a valid time range for simulation and adjusts the start time for rounding purposes.
Author
Lars Hoffmann

Definition at line 6066 of file mptrac.c.

6068 {
6069
6070 /* Set timer... */
6071 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS");
6072
6073 /* Set start time... */
6074 if (ctl->direction == 1) {
6075 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
6076 if (ctl->t_stop > 1e99)
6077 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
6078 } else {
6079 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
6080 if (ctl->t_stop > 1e99)
6081 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
6082 }
6083
6084 /* Check time interval... */
6085 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
6086 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
6087
6088 /* Round start time... */
6089 if (ctl->direction == 1)
6090 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
6091 else
6092 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
6093}

◆ module_tracer_chem()

void module_tracer_chem ( const ctl_t ctl,
const cache_t cache,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm 
)

Simulate chemical reactions involving long-lived atmospheric tracers.

This function simulates chemical reactions involving atmospheric tracers, such as CFC-10, CFC-11, CFC-12, and N2O. It calculates the change in tracer concentrations over time based on reaction rates and environmental factors such as temperature, ozone concentration, solar zenith angle, and O(1D) volume mixing ratio.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climatological data structure.
met0Pointer to the first meteorological data structure.
met1Pointer to the second meteorological data structure.
atmPointer to the atmospheric data structure containing particle information.
Note
The function assumes that the necessary control structure (ctl), climatological data structure (clim), meteorological data structures (met0, met1), and atmospheric data structure (atm) have been initialized and are accessible.
Chemical reactions involving CFC-10, CFC-11, CFC-12, and N2O are simulated for each particle in the atmospheric data structure.
The function calculates reaction rates based on temperature, solar zenith angle, total column ozone, and the volume mixing ratio of O(1D).
The exponential decay of tracer concentrations due to chemical reactions is calculated using reaction rate coefficients and the time step (dt) for each particle.
If the particle has a quantity flag for the tracer species (e.g., ctl->qnt_Cccl4, ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o), the function updates the concentration of the tracer based on the exponential decay.
Author
Mingzhao Liu
Lars Hoffmann

Definition at line 6097 of file mptrac.c.

6103 {
6104
6105 if (ctl->met_coord_type != 0)
6106 ERRMSG("Only lat/lon grid supported");
6107
6108 /* Set timer... */
6109 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS");
6110
6111 /* Loop over particles... */
6112 PARTICLE_LOOP(0, atm->np, 1,
6113 "acc data present(ctl,cache,clim,met0,met1,atm)") {
6114
6115 /* Get temperature... */
6116 double t;
6118 INTPOL_3D(t, 1);
6119
6120 /* Get molecular density... */
6121 const double M = MOLEC_DENS(atm->p[ip], t);
6122
6123 /* Get total column ozone... */
6124 double o3c;
6125 INTPOL_2D(o3c, 1);
6126
6127 /* Get solar zenith angle... */
6128 const double sza =
6129 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
6130
6131 /* Get O(1D) volume mixing ratio... */
6132 const double o1d =
6133 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
6134
6135 /* Reactions for CFC-10... */
6136 if (ctl->qnt_Cccl4 >= 0) {
6137 const double K_o1d =
6139 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
6140 atm->p[ip], sza, o3c);
6141 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6142 }
6143
6144 /* Reactions for CFC-11... */
6145 if (ctl->qnt_Cccl3f >= 0) {
6146 const double K_o1d =
6148 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
6149 atm->p[ip], sza, o3c);
6150 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6151 }
6152
6153 /* Reactions for CFC-12... */
6154 if (ctl->qnt_Cccl2f2 >= 0) {
6155 const double K_o1d =
6157 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
6158 atm->p[ip], sza, o3c);
6159 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6160 }
6161
6162 /* Reactions for N2O... */
6163 if (ctl->qnt_Cn2o >= 0) {
6164 const double K_o1d =
6166 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
6167 atm->p[ip], sza, o3c);
6168 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6169 }
6170 }
6171}
double clim_photo(const double rate[CP][CSZA][CO3], const clim_photo_t *photo, const double p, const double sza, const double o3c)
Calculates the photolysis rate for a given set of atmospheric conditions.
Definition: mptrac.c:156
#define O1D_RATE_CFC12_B
O(1D) reaction temperature parameter for CFC-12 [K].
Definition: mptrac.h:414
#define O1D_RATE_N2O_A
O(1D) reaction pre-factor for N2O [cm^3/s].
Definition: mptrac.h:419
#define O1D_RATE_CFC12_A
O(1D) reaction pre-factor for CFC-12 [cm^3/s].
Definition: mptrac.h:409
#define O1D_RATE_N2O_B
O(1D) reaction temperature parameter for N2O [K].
Definition: mptrac.h:424
#define O1D_RATE_CCL4_B
O(1D) reaction temperature parameter for CCl4 [K].
Definition: mptrac.h:394
#define O1D_RATE_CFC11_A
O(1D) reaction pre-factor for CFC-11 [cm^3/s].
Definition: mptrac.h:399
#define O1D_RATE_CCL4_A
O(1D) reaction pre-factor for CCl4 [cm^3/s].
Definition: mptrac.h:389
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:733
#define O1D_RATE_CFC11_B
O(1D) reaction temperature parameter for CFC-11 [K].
Definition: mptrac.h:404
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3709
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3706
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3700
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3703
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3805
Here is the call graph for this function:

◆ module_wet_depo()

void module_wet_depo ( const ctl_t ctl,
const cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Perform wet deposition calculations for air parcels.

This function calculates the wet deposition process for each air parcel based on provided atmospheric and meteorological data. It estimates the precipitation rate and scavenging coefficients for particles and gases inside and below cloud layers. The scavenging coefficients are used to calculate the exponential decay of mass or volume mixing ratio over time due to wet deposition.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the initial meteorological data structure.
met1Pointer to the updated meteorological data structure.
atmPointer to the atmospheric data structure containing air parcel information.
Note
The function calculates the wet deposition process for particles and gases based on precipitation rate and scavenging coefficients inside and below cloud layers.
It estimates the exponential decay of mass or volume mixing ratio over time due to wet deposition.
For exponential form A and B coefficients see Bakels et al. (2024, Table B2).
For Henry's law constants see Sander (2023) or https://henrys-law.org/.
Some species (e.g. SO2) require an effective Henry constant to account not only for physical solubility in water but also for chemical reactions, such as hydrolysis and ionization, which significantly enhance dissolution in aqueous solutions.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 6175 of file mptrac.c.

6180 {
6181
6182 /* Set timer... */
6183 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS");
6184
6185 /* Check quantity flags... */
6186 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
6187 ERRMSG("Module needs quantity mass or volume mixing ratio!");
6188
6189 /* Loop over particles... */
6190 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
6191
6192 /* Check whether particle is below cloud top... */
6193 double pct;
6195 INTPOL_2D(pct, 1);
6196 if (!isfinite(pct) || atm->p[ip] <= pct)
6197 continue;
6198
6199 /* Get cloud bottom pressure... */
6200 double pcb;
6201 INTPOL_2D(pcb, 0);
6202
6203 /* Estimate precipitation rate (Pisso et al., 2019)... */
6204 double cl;
6205 INTPOL_2D(cl, 0);
6206 const double Is =
6207 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
6208 if (Is < 0.01)
6209 continue;
6210
6211 /* Check whether particle is inside or below cloud... */
6212 double lwc, rwc, iwc, swc;
6213 INTPOL_3D(lwc, 1);
6214 INTPOL_3D(rwc, 0);
6215 INTPOL_3D(iwc, 0);
6216 INTPOL_3D(swc, 0);
6217 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
6218
6219 /* Get temperature... */
6220 double t;
6221 INTPOL_3D(t, 0);
6222
6223 /* Calculate in-cloud scavenging coefficient... */
6224 double lambda = 0;
6225 if (inside) {
6226
6227 /* Calculate retention factor... */
6228 double eta;
6229 if (t > WET_DEPO_T_LIQUID)
6230 eta = 1;
6231 else if (t <= WET_DEPO_T_ICE)
6232 eta = ctl->wet_depo_ic_ret_ratio;
6233 else
6234 eta =
6236 ctl->wet_depo_ic_ret_ratio, t);
6237
6238 /* Use exponential dependency for particles (Bakels et al., 2024)... */
6239 if (ctl->wet_depo_ic_a > 0)
6240 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
6241
6242 /* Use Henry's law for gases... */
6243 else if (ctl->wet_depo_ic_h[0] > 0) {
6244
6245 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
6246 double h = ctl->wet_depo_ic_h[0]
6247 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / CHEM_REF_TEMP));
6248
6249 /* Use effective Henry's constant for SO2
6250 (Berglen, 2004; Simpson, 2012)... */
6251 if (ctl->wet_depo_so2_ph > 0) {
6252 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
6253 const double K_1 = SO2_DISS_K1_REF
6254 * exp(SO2_DISS_K1_TEMP * (1. / t - 1. / CHEM_REF_TEMP));
6255 const double K_2 = SO2_DISS_K2_REF
6256 * exp(SO2_DISS_K2_TEMP * (1. / t - 1. / CHEM_REF_TEMP));
6257 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
6258 }
6259
6260 /* Estimate depth of cloud layer... */
6261 const double dz = 1e3 * (Z(pct) - Z(pcb));
6262
6263 /* Calculate scavenging coefficient... */
6264 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
6265 }
6266 }
6267
6268 /* Calculate below-cloud scavenging coefficient... */
6269 else {
6270
6271 /* Calculate retention factor... */
6272 double eta;
6273 if (t > WET_DEPO_T_LIQUID_BC)
6274 eta = 1;
6275 else
6276 eta = ctl->wet_depo_bc_ret_ratio;
6277
6278 /* Use exponential dependency for particles (Bakels et al., 2024)... */
6279 if (ctl->wet_depo_bc_a > 0)
6280 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
6281
6282 /* Use Henry's law for gases... */
6283 else if (ctl->wet_depo_bc_h[0] > 0) {
6284
6285 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
6286 const double h = ctl->wet_depo_bc_h[0]
6287 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / CHEM_REF_TEMP));
6288
6289 /* Estimate depth of cloud layer... */
6290 const double dz = 1e3 * (Z(pct) - Z(pcb));
6291
6292 /* Calculate scavenging coefficient... */
6293 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
6294 }
6295 }
6296
6297 /* Calculate exponential decay of mass... */
6298 const double aux = exp(-cache->dt[ip] * lambda);
6299 if (ctl->qnt_m >= 0) {
6300 if (ctl->qnt_mloss_wet >= 0)
6301 atm->q[ctl->qnt_mloss_wet][ip]
6302 += atm->q[ctl->qnt_m][ip] * (1 - aux);
6303 atm->q[ctl->qnt_m][ip] *= aux;
6304 if (ctl->qnt_loss_rate >= 0)
6305 atm->q[ctl->qnt_loss_rate][ip] += lambda;
6306 }
6307 if (ctl->qnt_vmr >= 0)
6308 atm->q[ctl->qnt_vmr][ip] *= aux;
6309 }
6310}
#define SO2_DISS_K2_TEMP
Temperature dependence of the second SO2 dissociation constant [K].
Definition: mptrac.h:444
#define SO2_DISS_K2_REF
Second SO2 dissociation constant at CHEM_REF_TEMP [mol/L].
Definition: mptrac.h:439
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:3266
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:3260
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2674
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:3278
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3275
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3272
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:3269
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:3263

◆ mptrac_alloc()

void mptrac_alloc ( ctl_t **  ctl,
cache_t **  cache,
clim_t **  clim,
met_t **  met0,
met_t **  met1,
atm_t **  atm,
depo_t **  depo,
dd_t **  dd 
)

Allocates and initializes memory resources for MPTRAC.

This function handles memory allocation for various data structures and sets up GPU resources if available. It also creates the necessary data regions on GPUs for OpenACC-enabled execution. Each output parameter is optional; pass NULL for structures that are not needed.

Parameters
[out]ctlPointer to the control structure (ctl_t).
[out]cachePointer to the cache structure (cache_t).
[out]climPointer to the climatology structure (clim_t).
[out]met0Pointer to the first meteorology structure (met_t).
[out]met1Pointer to the second meteorology structure (met_t).
[out]atmPointer to the atmospheric structure (atm_t).
[out]depoPointer to the radionuclide ground-inventory structure (depo_t).
[out]ddpointer to an dd_t structure containing MPI information, including rank and neighbours.
Note
This function uses OpenACC for GPU initialization and memory management. If OpenACC is not enabled, the GPU-specific code is ignored.
Precondition
The function requires an environment supporting OpenACC for GPU operations. MPI support is optional but assumed if compiled with MPI.
Postcondition
Allocated structures are ready for use, and data regions on GPUs are initialized if OpenACC is enabled.
Exceptions
Runtimeerror if no GPU devices are available when OpenACC is enabled.
Author
Lars Hoffmann

Definition at line 6314 of file mptrac.c.

6322 {
6323
6324 /* Initialize GPU... */
6325#ifdef _OPENACC
6326 if (ctl != NULL || cache != NULL || clim != NULL || met0 != NULL
6327 || met1 != NULL || atm != NULL || depo != NULL || dd != NULL) {
6328 SELECT_TIMER("ACC_INIT", "INIT");
6329 if (acc_get_num_devices(acc_device_nvidia) <= 0)
6330 ERRMSG("Not running on a GPU device!");
6331 acc_device_t device_type = acc_get_device_type();
6332 acc_init(device_type);
6333 }
6334#endif
6335
6336 /* Allocate... */
6337 SELECT_TIMER("ALLOC", "MEMORY");
6338 if (ctl != NULL)
6339 ALLOC(*ctl, ctl_t, 1);
6340 if (cache != NULL)
6341 ALLOC(*cache, cache_t, 1);
6342 if (clim != NULL)
6343 ALLOC(*clim, clim_t, 1);
6344 if (met0 != NULL)
6345 ALLOC(*met0, met_t, 1);
6346 if (met1 != NULL)
6347 ALLOC(*met1, met_t, 1);
6348 if (atm != NULL)
6349 ALLOC(*atm, atm_t, 1);
6350 if (depo != NULL)
6351 ALLOC(*depo, depo_t, 1);
6352 if (dd != NULL)
6353 ALLOC(*dd, dd_t, 1);
6354
6355 /* Create data region on GPU... */
6356#ifdef _OPENACC
6357 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY");
6358 if (ctl != NULL) {
6359 ctl_t *ctlup = *ctl;
6360#pragma acc enter data create(ctlup[:1])
6361 }
6362 if (cache != NULL) {
6363 cache_t *cacheup = *cache;
6364#pragma acc enter data create(cacheup[:1])
6365 }
6366 if (clim != NULL) {
6367 clim_t *climup = *clim;
6368#pragma acc enter data create(climup[:1])
6369 }
6370 if (met0 != NULL) {
6371 met_t *met0up = *met0;
6372#pragma acc enter data create(met0up[:1])
6373 }
6374 if (met1 != NULL) {
6375 met_t *met1up = *met1;
6376#pragma acc enter data create(met1up[:1])
6377 }
6378 if (atm != NULL) {
6379 atm_t *atmup = *atm;
6380#pragma acc enter data create(atmup[:1])
6381 }
6382 if (depo != NULL) {
6383 depo_t *depoup = *depo;
6384#pragma acc enter data create(depoup[:1])
6385 }
6386#ifdef DD
6387 if (dd != NULL) {
6388 dd_t *ddup = *dd;
6389#pragma acc enter data create(ddup[:1])
6390 }
6391#endif
6392#endif
6393}
Air parcel data.
Definition: mptrac.h:3565
Cache data structure.
Definition: mptrac.h:3620
Climatological data.
Definition: mptrac.h:3787
Control parameters.
Definition: mptrac.h:2493
Domain decomposition data structure.
Definition: mptrac.h:4023
Ground inventories of deposited radionuclides.
Definition: mptrac.h:3656
Meteo data structure.
Definition: mptrac.h:3846

◆ mptrac_free()

void mptrac_free ( ctl_t ctl,
cache_t cache,
clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
depo_t depo,
dd_t dd 
)

Frees memory resources allocated for MPTRAC.

This function releases the memory allocated for various data structures and deletes any associated data regions on GPUs if OpenACC is enabled. Every argument may be NULL.

Parameters
[in]ctlPointer to the control structure (ctl_t) to be freed.
[in]cachePointer to the cache structure (cache_t) to be freed.
[in]climPointer to the climatology structure (clim_t) to be freed.
[in]met0Pointer to the first meteorology structure (met_t) to be freed.
[in]met1Pointer to the second meteorology structure (met_t) to be freed.
[in]atmPointer to the atmospheric structure (atm_t) to be freed.
[in]depoPointer to the radionuclide ground-inventory structure (depo_t) to be freed.
[in]ddPointer to an dd_t structure containing MPI information, including rank and neighbours.
Note
This function uses OpenACC for GPU memory management. If OpenACC is not enabled, the GPU-specific code is ignored.
Precondition
Non-NULL input pointers must have been returned through the corresponding argument of mptrac_alloc().
Postcondition
All input pointers are freed, and the associated data regions on GPUs are deleted if OpenACC is enabled.
Warning
Ensure that the input pointers are not used after calling this function as they will be invalidated.
Author
Lars Hoffmann

Definition at line 6397 of file mptrac.c.

6405 {
6406
6407 /* Delete data region on GPU... */
6408#ifdef _OPENACC
6409 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY");
6410 if (ctl != NULL) {
6411#pragma acc exit data delete(ctl[:1])
6412 }
6413 if (cache != NULL) {
6414#pragma acc exit data delete(cache[:1])
6415 }
6416 if (clim != NULL) {
6417#pragma acc exit data delete(clim[:1])
6418 }
6419 if (met0 != NULL) {
6420#pragma acc exit data delete(met0[:1])
6421 }
6422 if (met1 != NULL) {
6423#pragma acc exit data delete(met1[:1])
6424 }
6425 if (atm != NULL) {
6426#pragma acc exit data delete(atm[:1])
6427 }
6428 if (depo != NULL) {
6429#pragma acc exit data delete(depo[:1])
6430 }
6431#ifdef DD
6432 if (dd != NULL) {
6433#pragma acc exit data delete(dd[:1])
6434 }
6435#endif
6436#endif
6437
6438 /* Free... */
6439 SELECT_TIMER("FREE", "MEMORY");
6440 free(atm);
6441 free(depo);
6442 free(ctl);
6443 free(cache);
6444 free(clim);
6445 free(met0);
6446 free(met1);
6447
6448 /* Free MPI datatype... */
6449#ifdef DD
6450 if (dd != NULL)
6451 MPI_Type_free(&dd->MPI_Particle);
6452#endif
6453 free(dd);
6454}

◆ mptrac_get_met()

void mptrac_get_met ( ctl_t ctl,
clim_t clim,
const double  t,
met_t **  met0,
met_t **  met1,
dd_t dd 
)

Retrieves meteorological data for the specified time.

This function retrieves meteorological data for the given time t and updates the provided pointers to the met0 and met1 structures accordingly. It handles both the initialization and subsequent updates of the meteorological data based on the direction of time integration.

Parameters
ctlPointer to the control structure containing configuration settings.
climPointer to the climate structure.
tThe current time for which meteorological data is to be retrieved.
met0Pointer to the pointer of the first meteorological data structure.
met1Pointer to the pointer of the second meteorological data structure.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.

The function performs the following steps:

  • Initializes meteorological data on the first call or when the simulation restarts.
  • Reads new meteorological data when advancing forward or backward in time.
  • Swaps pointers to manage double buffering of the meteorological data.
  • Performs caching to optimize subsequent data retrieval.
  • Ensures consistency of the meteorological grids.
Note
This function utilizes GPU acceleration with OpenACC directives if enabled.
Ensure that ctl, clim, met0, and met1 are properly initialized before calling this function.
See also
get_met_filename
read_met
SELECT_TIMER
LOG
ERRMSG
WARN
Author
Lars Hoffmann

Definition at line 6458 of file mptrac.c.

6464 {
6465
6466 static int init;
6467
6468 met_t *mets;
6469
6470 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
6471
6472 /* Set timer... */
6473 SELECT_TIMER("GET_MET", "INPUT");
6474
6475 /* Init... */
6476 if (t == ctl->t_start || !init) {
6477 init = 1;
6478
6479 /* Read meteo data... */
6480 get_met_filename(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
6481 ctl->metbase, ctl->dt_met, filename);
6482 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
6483 ERRMSG("Cannot open file!");
6484
6485 get_met_filename(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
6486 ctl->metbase, ctl->dt_met, filename);
6487 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
6488 ERRMSG("Cannot open file!");
6489
6490 /* Update GPU... */
6491 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
6492 SELECT_TIMER("GET_MET", "INPUT");
6493
6494 /* Caching... */
6495 if (ctl->met_cache && t != ctl->t_stop) {
6496 get_met_filename(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
6497 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
6498 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6499 LOG(1, "Caching: %s", cachefile);
6500 if (system(cmd) != 0)
6501 WARN("Caching command failed!");
6502 }
6503 }
6504
6505 /* Read new data for forward trajectories... */
6506 if (t > (*met1)->time) {
6507
6508 /* Pointer swap... */
6509 mets = *met1;
6510 *met1 = *met0;
6511 *met0 = mets;
6512
6513 /* Read new meteo data... */
6514 get_met_filename(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
6515 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
6516 ERRMSG("Cannot open file!");
6517
6518 /* Update GPU... */
6519 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
6520 SELECT_TIMER("GET_MET", "INPUT");
6521
6522 /* Caching... */
6523 if (ctl->met_cache && t != ctl->t_stop) {
6524 get_met_filename(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
6525 cachefile);
6526 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6527 LOG(1, "Caching: %s", cachefile);
6528 if (system(cmd) != 0)
6529 WARN("Caching command failed!");
6530 }
6531 }
6532
6533 /* Read new data for backward trajectories... */
6534 if (t < (*met0)->time) {
6535
6536 /* Pointer swap... */
6537 mets = *met1;
6538 *met1 = *met0;
6539 *met0 = mets;
6540
6541 /* Read new meteo data... */
6542 get_met_filename(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
6543 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
6544 ERRMSG("Cannot open file!");
6545
6546 /* Update GPU... */
6547 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
6548 SELECT_TIMER("GET_MET", "INPUT");
6549
6550 /* Caching... */
6551 if (ctl->met_cache && t != ctl->t_stop) {
6552 get_met_filename(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
6553 cachefile);
6554 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6555 LOG(1, "Caching: %s", cachefile);
6556 if (system(cmd) != 0)
6557 WARN("Caching command failed!");
6558 }
6559 }
6560
6561 if ((*met0)->coord_type != (*met1)->coord_type)
6562 ERRMSG("Coordinate types do not match!");
6563
6564 /* Check that grids are consistent... */
6565 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
6566 if ((*met0)->nx != (*met1)->nx
6567 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
6568 ERRMSG("Meteo grid dimensions do not match!");
6569 for (int ix = 0; ix < (*met0)->nx; ix++)
6570 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
6571 ERRMSG("Meteo grid longitudes do not match!");
6572 for (int iy = 0; iy < (*met0)->ny; iy++)
6573 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
6574 ERRMSG("Meteo grid latitudes do not match!");
6575 for (int ip = 0; ip < (*met0)->np; ip++)
6576 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
6577 ERRMSG("Meteo grid pressure levels do not match!");
6578 }
6579}
void get_met_filename(const ctl_t *ctl, const double t, const int direct, const char *metbase, const double dt_met, char *filename)
Generates a formatted filename for meteorological data files based on the input parameters.
Definition: mptrac.c:2619
int mptrac_read_met(const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met, dd_t *dd)
Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.
Definition: mptrac.c:7767
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2372
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:3005
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2840
Here is the call graph for this function:

◆ mptrac_init()

void mptrac_init ( ctl_t ctl,
cache_t cache,
clim_t clim,
atm_t atm,
depo_t depo,
const int  ntask 
)

Initializes the MPTRAC model and its associated components.

This function sets up the necessary components and subsystems for the MPTRAC module, including timesteps, random number generation, and GPU memory updates.

Parameters
ctlPointer to the control structure containing configuration and state information.
cachePointer to the cache structure used for data storage and retrieval.
climPointer to the climatology structure containing climate-related data.
atmPointer to the atmospheric structure containing atmospheric state data.
depoPointer to inventories allocated and zero-initialized by mptrac_alloc().
ntaskNumber of tasks or threads to initialize for the random number generator.

The function performs the following operations:

  • Initializes the timesteps using the module_timesteps_init function.
  • Initializes the random number generator using the module_rng_init function.
  • Updates GPU memory using the mptrac_update_device function.
Author
Lars Hoffmann

Definition at line 6583 of file mptrac.c.

6589 {
6590
6591 /* Initialize timesteps... */
6592 module_timesteps_init(ctl, atm);
6593
6594 /* Initialize random number generator... */
6595 module_rng_init(ntask);
6596
6597 /* Update GPU memory... */
6598 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
6599#ifdef _OPENACC
6600#pragma acc update device(depo[:1])
6601#else
6602 (void) depo;
6603#endif
6604}
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:6066
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:5743
Here is the call graph for this function:

◆ mptrac_read_atm()

int mptrac_read_atm ( const char *  filename,
const ctl_t ctl,
atm_t atm 
)

Reads air parcel data from a specified file into the given atmospheric structure.

This function reads air parcel data from a file and populates the provided atm_t structure based on the type of data specified in the ctl_t control structure. It supports various data formats including ASCII, binary, netCDF, and CLaMS.

Parameters
filenameThe name of the file containing the atmospheric data.
ctlA pointer to the control structure (ctl_t) that specifies the type of data.
atmA pointer to the atmospheric structure (atm_t) that will be populated with the data.
Returns
Returns 1 on success, and 0 on failure.

This function performs the following steps:

  • Sets a timer for performance measurement.
  • Initializes the atmospheric structure.
  • Logs the file being read.
  • Reads data from the file based on the specified type (ctl->atm_type):
    • 0 for ASCII data
    • 1 for binary data
    • 2 for netCDF data
    • 3 or 4 for CLaMS data
  • Handles errors if the data type is not supported.
  • Checks the result of the data reading function and ensures data was read successfully.
  • Logs information about the number of air parcels and the ranges of various parameters (time, altitude, pressure, longitude, latitude, and other quantities).

The function utilizes several helper functions and macros:

  • SELECT_TIMER for setting the timer.
  • LOG for logging information.
  • ERRMSG for handling error messages.
  • gsl_stats_minmax for calculating minimum and maximum values.
  • Z for converting altitude.
Author
Lars Hoffmann

Definition at line 6608 of file mptrac.c.

6611 {
6612
6613 int result;
6614
6615 /* Set timer... */
6616 SELECT_TIMER("READ_ATM", "INPUT");
6617
6618 /* Init... */
6619 atm->np = 0;
6620
6621 /* Write info... */
6622 LOG(1, "Read atmospheric data: %s", filename);
6623
6624 /* Read ASCII data... */
6625 if (ctl->atm_type == 0)
6626 result = read_atm_asc(filename, ctl, atm);
6627
6628 /* Read binary data... */
6629 else if (ctl->atm_type == 1)
6630 result = read_atm_bin(filename, ctl, atm);
6631
6632 /* Read netCDF data... */
6633 else if (ctl->atm_type == 2)
6634 result = read_atm_nc(filename, ctl, atm);
6635
6636 /* Read CLaMS data... */
6637 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
6638 result = read_atm_clams(filename, ctl, atm);
6639
6640 /* Error... */
6641 else
6642 ERRMSG("Atmospheric data type not supported!");
6643
6644 /* Check result... */
6645 if (result != 1)
6646 return 0;
6647
6648 /* Check number of air parcels... */
6649 if (atm->np < 1)
6650 ERRMSG("Can not read any data!");
6651
6652 /* Write info... */
6653 double mini, maxi;
6654 LOG(2, "Number of particles: %d", atm->np);
6655 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6656 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6657 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6658 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6659 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6660 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6661 LOG(2, "%s range: %g ... %g %s",
6662 ctl->met_coord_type == 0 ? "Longitude" : "X coordinate", mini, maxi,
6663 ctl->met_coord_type == 0 ? "deg" : "m");
6664 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6665 LOG(2, "%s range: %g ... %g %s",
6666 ctl->met_coord_type == 0 ? "Latitude" : "Y coordinate", mini, maxi,
6667 ctl->met_coord_type == 0 ? "deg" : "m");
6668 for (int iq = 0; iq < ctl->nq; iq++) {
6669 char msg[5 * LEN];
6670 sprintf(msg, "Quantity %s range: %s ... %s %s",
6671 ctl->qnt_name[iq], ctl->qnt_format[iq],
6672 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6673 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6674 LOG(2, msg, mini, maxi);
6675 }
6676
6677 /* Return success... */
6678 return 1;
6679}
int read_atm_nc(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a generic netCDF file and populates the given atmospheric structure.
Definition: mptrac.c:8566
int read_atm_bin(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a binary file and populates the given atmospheric structure.
Definition: mptrac.c:8447
int read_atm_clams(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads atmospheric data from a CLAMS NetCDF file.
Definition: mptrac.c:8503
int read_atm_asc(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from an ASCII file and populates the given atmospheric structure.
Definition: mptrac.c:8405
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2512
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3328
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2509
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2503
Here is the call graph for this function:

◆ mptrac_read_clim()

void mptrac_read_clim ( const ctl_t ctl,
clim_t clim 
)

Reads various climatological data and populates the given climatology structure.

This function reads a range of climatological datasets based on the specified control settings and stores the data in the provided clim_t structure. It handles initialization of tropopause climatology, photolysis rates, and multiple gas species' climatologies and time series.

Parameters
ctlA pointer to the control structure (ctl_t) that specifies file names and parameters for climatology data.
climA pointer to the climatology structure (clim_t) that will be populated with the data.

This function performs the following steps:

  • Sets a timer for reading climatology data.
  • Initializes the tropopause climatology.
  • Reads photolysis rates if specified in ctl.
  • Reads HNO3 climatology if specified in ctl.
  • Reads OH climatology if specified in ctl and applies a diurnal correction if specified.
  • Reads H2O2, HO2, O(1D) climatologies if specified in ctl.
  • Reads time series data for various gases (CFC-10, CFC-11, CFC-12, N2O, SF6) if specified in ctl.

The function utilizes several helper functions:

  • clim_tropo_init for initializing tropopause climatology.
  • read_clim_photo for reading photolysis rates.
  • read_clim_zm for reading zonal mean climatologies.
  • clim_oh_diurnal_correction for applying diurnal correction to OH climatology.
  • read_clim_ts for reading time series data.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 6683 of file mptrac.c.

6685 {
6686
6687 /* Set timer... */
6688 SELECT_TIMER("READ_CLIM", "INPUT");
6689
6690 /* Init tropopause climatology... */
6691 clim_tropo_init(clim);
6692
6693 /* Read photolysis rates... */
6694 if (ctl->clim_photo[0] != '-')
6695 read_clim_photo(ctl->clim_photo, &clim->photo);
6696
6697 /* Read HNO3 climatology... */
6698 if (ctl->clim_hno3_filename[0] != '-')
6699 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
6700
6701 /* Read OH climatology... */
6702 if (ctl->clim_oh_filename[0] != '-') {
6703 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
6704 if (ctl->oh_chem_beta > 0)
6705 clim_oh_diurnal_correction(ctl, clim);
6706 }
6707
6708 /* Read H2O2 climatology... */
6709 if (ctl->clim_h2o2_filename[0] != '-')
6710 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
6711
6712 /* Read HO2 climatology... */
6713 if (ctl->clim_ho2_filename[0] != '-')
6714 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
6715
6716 /* Read O(1D) climatology... */
6717 if (ctl->clim_o1d_filename[0] != '-')
6718 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
6719
6720 /* Read CFC-10 time series... */
6721 if (ctl->clim_ccl4_timeseries[0] != '-')
6723
6724 /* Read CFC-11 time series... */
6725 if (ctl->clim_ccl3f_timeseries[0] != '-')
6727
6728 /* Read CFC-12 time series... */
6729 if (ctl->clim_ccl2f2_timeseries[0] != '-')
6731
6732 /* Read N2O time series... */
6733 if (ctl->clim_n2o_timeseries[0] != '-')
6734 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
6735
6736 /* Read SF6 time series... */
6737 if (ctl->clim_sf6_timeseries[0] != '-')
6738 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
6739}
void read_clim_photo(const char *filename, clim_photo_t *photo)
Reads photolysis rates from a NetCDF file and populates the given photolysis structure.
Definition: mptrac.c:8599
int read_clim_ts(const char *filename, clim_ts_t *ts)
Reads a climatological time series from a file and populates the given time series structure.
Definition: mptrac.c:8718
void read_clim_zm(const char *filename, const char *varname, clim_zm_t *zm)
Reads zonally averaged climatological data from a netCDF file and populates the given structure.
Definition: mptrac.c:8772
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:241
void clim_oh_diurnal_correction(const ctl_t *ctl, clim_t *clim)
Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data.
Definition: mptrac.c:124
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:3143
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:3146
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:3131
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:3140
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:3137
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:3134
Here is the call graph for this function:

◆ mptrac_read_ctl()

void mptrac_read_ctl ( const char *  filename,
int  argc,
char *  argv[],
ctl_t ctl 
)

Reads control parameters from a configuration file and populates the given structure.

This function reads control parameters from a specified configuration file and command line arguments, populating the provided ctl_t structure with the parsed data. It handles a wide range of parameters, performing necessary checks and providing default values where applicable.

Parameters
filenameA string containing the path to the configuration file.
argcAn integer representing the number of command line arguments.
argvAn array of strings containing the command line arguments.
ctlA pointer to the structure (ctl_t) that will be populated with the control parameters.

The function performs the following steps:

  • Sets a timer for reading the control file.
  • Logs information about the MPTRAC executable version and compilation details.
  • Initializes quantity indices.
  • Reads and sets various control parameters such as quantities, vertical coordinates, time steps, meteorological data, sorting options, isosurface parameters, random number generator type, advection parameters, diffusion parameters, convection parameters, boundary conditions, species parameters, molar mass, OH chemistry parameters, H2O2 chemistry parameters, KPP chemistry parameters, first order tracer chemistry parameters, wet deposition parameters, dry deposition parameters, climatological data paths, mixing parameters, chemistry grid parameters, exponential decay parameters, PSC analysis parameters, output parameters for atmospheric data, CSI data, ensemble data, grid data, profile data, sample data, station data, and VTK data.
Author
Lars Hoffmann

Definition at line 6743 of file mptrac.c.

6747 {
6748
6749 /* Set timer... */
6750 SELECT_TIMER("READ_CTL", "INPUT");
6751
6752 /* Write info... */
6753 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
6754 "(executable: %s | version: %s | compiled: %s, %s)\n",
6755 argv[0], VERSION, __DATE__, __TIME__);
6756
6757 /* Initialize quantity indices... */
6758 ctl->qnt_idx = -1;
6759 ctl->qnt_ens = -1;
6760 ctl->qnt_stat = -1;
6761 ctl->qnt_m = -1;
6762 ctl->qnt_vmr = -1;
6763 ctl->qnt_rp = -1;
6764 ctl->qnt_rhop = -1;
6765 ctl->qnt_ps = -1;
6766 ctl->qnt_ts = -1;
6767 ctl->qnt_zs = -1;
6768 ctl->qnt_us = -1;
6769 ctl->qnt_vs = -1;
6770 ctl->qnt_ess = -1;
6771 ctl->qnt_nss = -1;
6772 ctl->qnt_shf = -1;
6773 ctl->qnt_lsm = -1;
6774 ctl->qnt_sst = -1;
6775 ctl->qnt_pbl = -1;
6776 ctl->qnt_pt = -1;
6777 ctl->qnt_tt = -1;
6778 ctl->qnt_zt = -1;
6779 ctl->qnt_h2ot = -1;
6780 ctl->qnt_zg = -1;
6781 ctl->qnt_p = -1;
6782 ctl->qnt_t = -1;
6783 ctl->qnt_rho = -1;
6784 ctl->qnt_u = -1;
6785 ctl->qnt_v = -1;
6786 ctl->qnt_w = -1;
6787 ctl->qnt_h2o = -1;
6788 ctl->qnt_o3 = -1;
6789 ctl->qnt_lwc = -1;
6790 ctl->qnt_rwc = -1;
6791 ctl->qnt_iwc = -1;
6792 ctl->qnt_swc = -1;
6793 ctl->qnt_cc = -1;
6794 ctl->qnt_pct = -1;
6795 ctl->qnt_pcb = -1;
6796 ctl->qnt_cl = -1;
6797 ctl->qnt_plcl = -1;
6798 ctl->qnt_plfc = -1;
6799 ctl->qnt_pel = -1;
6800 ctl->qnt_cape = -1;
6801 ctl->qnt_cin = -1;
6802 ctl->qnt_o3c = -1;
6803 ctl->qnt_hno3 = -1;
6804 ctl->qnt_oh = -1;
6805 ctl->qnt_h2o2 = -1;
6806 ctl->qnt_ho2 = -1;
6807 ctl->qnt_o1d = -1;
6808 ctl->qnt_mloss_oh = -1;
6809 ctl->qnt_mloss_h2o2 = -1;
6810 ctl->qnt_mloss_kpp = -1;
6811 ctl->qnt_mloss_wet = -1;
6812 ctl->qnt_mloss_dry = -1;
6813 ctl->qnt_mloss_decay = -1;
6814 ctl->qnt_loss_rate = -1;
6815 ctl->qnt_psat = -1;
6816 ctl->qnt_psice = -1;
6817 ctl->qnt_pw = -1;
6818 ctl->qnt_sh = -1;
6819 ctl->qnt_rh = -1;
6820 ctl->qnt_rhice = -1;
6821 ctl->qnt_theta = -1;
6822 ctl->qnt_zeta = -1;
6823 ctl->qnt_zeta_d = -1;
6824 ctl->qnt_zeta_dot = -1;
6825 ctl->qnt_eta = -1;
6826 ctl->qnt_eta_d = -1;
6827 ctl->qnt_eta_dot = -1;
6828 ctl->qnt_tvirt = -1;
6829 ctl->qnt_lapse = -1;
6830 ctl->qnt_vh = -1;
6831 ctl->qnt_vz = -1;
6832 ctl->qnt_pv = -1;
6833 ctl->qnt_tdew = -1;
6834 ctl->qnt_tice = -1;
6835 ctl->qnt_tsts = -1;
6836 ctl->qnt_tnat = -1;
6837 ctl->qnt_Cx = -1;
6838 ctl->qnt_Ch2o = -1;
6839 ctl->qnt_Co3 = -1;
6840 ctl->qnt_Cco = -1;
6841 ctl->qnt_Coh = -1;
6842 ctl->qnt_Ch = -1;
6843 ctl->qnt_Cho2 = -1;
6844 ctl->qnt_Ch2o2 = -1;
6845 ctl->qnt_Co1d = -1;
6846 ctl->qnt_Co3p = -1;
6847 ctl->qnt_Cccl4 = -1;
6848 ctl->qnt_Cccl3f = -1;
6849 ctl->qnt_Cccl2f2 = -1;
6850 ctl->qnt_Cn2o = -1;
6851 ctl->qnt_Csf6 = -1;
6852 ctl->qnt_aoa = -1;
6853 ctl->qnt_Arn222 = -1;
6854 ctl->qnt_Apb210 = -1;
6855 ctl->qnt_Abe7 = -1;
6856 ctl->qnt_Acs137 = -1;
6857 ctl->qnt_Ai131 = -1;
6858 ctl->qnt_Axe133 = -1;
6859 ctl->qnt_current_subdomain = -1;
6860 ctl->qnt_target_subdomain = -1;
6861
6862 /* Read quantities... */
6863 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
6864 if (ctl->nq > NQ)
6865 ERRMSG("Too many quantities!");
6866 for (int iq = 0; iq < ctl->nq; iq++) {
6867
6868 /* Read quantity name and format... */
6869 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
6870 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
6871 ctl->qnt_longname[iq]);
6872 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
6873 ctl->qnt_format[iq]);
6874 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
6875 sprintf(ctl->qnt_format[iq], "%%.2f");
6876
6877 /* Try to identify quantity... */
6878 SET_QNT(qnt_idx, "idx", "particle index", "-")
6879 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
6880 SET_QNT(qnt_stat, "stat", "station flag", "-")
6881 SET_QNT(qnt_m, "m", "mass", "kg")
6882 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
6883 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
6884 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
6885 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
6886 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
6887 SET_QNT(qnt_zs, "zs", "surface height", "km")
6888 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
6889 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
6890 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
6891 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
6892 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
6893 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
6894 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
6895 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
6896 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
6897 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
6898 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
6899 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
6900 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
6901 SET_QNT(qnt_p, "p", "pressure", "hPa")
6902 SET_QNT(qnt_t, "t", "temperature", "K")
6903 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
6904 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
6905 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
6906 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
6907 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
6908 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
6909 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
6910 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
6911 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
6912 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
6913 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
6914 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
6915 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
6916 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
6917 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
6918 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
6919 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
6920 SET_QNT(qnt_cape, "cape", "convective available potential energy",
6921 "J/kg")
6922 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
6923 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
6924 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
6925 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
6926 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
6927 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
6928 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
6929 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
6930 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
6931 "mass loss due to H2O2 chemistry", "kg")
6932 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
6933 "kg")
6934 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
6935 "kg")
6936 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
6937 "kg")
6938 SET_QNT(qnt_mloss_decay, "mloss_decay",
6939 "mass loss due to exponential decay", "kg")
6940 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
6941 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
6942 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
6943 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
6944 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
6945 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
6946 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
6947 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
6948 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
6949 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
6950 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
6951 "K/day")
6952 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
6953 SET_QNT(qnt_eta_d, "eta_d", "diagnosed eta coordinate", "1")
6954 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
6955 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
6956 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
6957 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
6958 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
6959 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
6960 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
6961 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
6962 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
6963 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
6964 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
6965 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
6966 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
6967 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
6968 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
6969 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
6970 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
6971 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
6972 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
6973 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
6974 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
6975 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
6976 "ppv")
6977 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
6978 "ppv")
6979 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
6980 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
6981 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
6982 SET_QNT(qnt_Arn222, "Arn222", "Rn-222 activity", "Bq")
6983 SET_QNT(qnt_Apb210, "Apb210", "Pb-210 activity", "Bq")
6984 SET_QNT(qnt_Abe7, "Abe7", "Be-7 activity", "Bq")
6985 SET_QNT(qnt_Acs137, "Acs137", "Cs-137 activity", "Bq")
6986 SET_QNT(qnt_Ai131, "Ai131", "I-131 activity", "Bq")
6987 SET_QNT(qnt_Axe133, "Axe133", "Xe-133 activity", "Bq")
6988 SET_QNT(qnt_current_subdomain, "current_subdomain",
6989 "current subdomain rank", "-")
6990 SET_QNT(qnt_target_subdomain, "target_subdomain",
6991 "target subdomain rank", "-")
6992 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
6993 }
6994
6995 ctl->met_coord_type =
6996 (int) scan_ctl(filename, argc, argv, "MET_COORD_TYPE", -1, "0", NULL);
6997 if (ctl->met_coord_type < 0 || ctl->met_coord_type > 1)
6998 ERRMSG("MET_COORD_TYPE must be 0 or 1!");
6999 ctl->met_utm_ref_lat = 0.0;
7000 ctl->met_utm_ref_lon = 0.0;
7001 if (ctl->met_coord_type == 1) {
7002 ctl->met_utm_ref_lat =
7003 scan_ctl(filename, argc, argv, "MET_UTM_REF_LAT", -1, "", NULL);
7004 ctl->met_utm_ref_lon =
7005 scan_ctl(filename, argc, argv, "MET_UTM_REF_LON", -1, "", NULL);
7006 }
7007
7008 /* Vertical coordinate and velocity... */
7009 ctl->advect_vert_coord =
7010 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
7011 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
7012 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
7013
7014 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
7015 ERRMSG("Add quantity zeta for diabatic advection!");
7016 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
7017 ERRMSG("Add quantity eta for etadot avection!");
7018
7019 ctl->met_vert_coord =
7020 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
7021 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
7022 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
7023 if (ctl->qnt_eta_d >= 0
7024 && ctl->met_vert_coord != 2 && ctl->met_vert_coord != 3)
7025 ERRMSG("Quantity eta_d requires full-level A and B coefficients!");
7026
7027 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
7028 ERRMSG
7029 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
7030 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
7031 ERRMSG
7032 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
7033
7034 ctl->met_gp2z =
7035 (int) scan_ctl(filename, argc, argv, "MET_GP2Z", -1, "0", NULL);
7036 if (ctl->met_gp2z != 0 && ctl->met_gp2z != 1)
7037 ERRMSG("Set MET_GP2Z to 0 or 1!");
7038
7039 /* Time steps of simulation... */
7040 ctl->direction =
7041 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
7042 if (ctl->direction != -1 && ctl->direction != 1)
7043 ERRMSG("Set DIRECTION to -1 or 1!");
7044 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
7045 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
7046
7047 /* Meteo data... */
7048 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
7049 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
7050 if (ctl->dt_mod > ctl->dt_met)
7051 ERRMSG("DT_MOD must not exceed DT_MET!");
7052 ctl->met_convention =
7053 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
7054 ctl->met_type =
7055 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
7056 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
7057 ERRMSG
7058 ("Please use meteo files in netcdf format for diabatic calculations.");
7059 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
7060 ERRMSG
7061 ("Please use meteo files in netcdf format for etadot calculations.");
7062 ctl->met_clams =
7063 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
7064 ctl->met_nc_scale =
7065 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
7066 ctl->met_nc_level =
7067 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
7068 ctl->met_nc_quant =
7069 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
7070 ctl->met_zstd_level =
7071 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "-3", NULL);
7072 ctl->met_zstd_nworkers =
7073 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_NWORKERS", -1, "4", NULL);
7074 ctl->met_lz4_accel =
7075 (int) scan_ctl(filename, argc, argv, "MET_LZ4_ACCEL", -1, "8", NULL);
7076 ctl->met_pck_zstd =
7077 (int) scan_ctl(filename, argc, argv, "MET_PCK_ZSTD", -1, "0", NULL);
7078 if (ctl->met_pck_zstd != 0 && ctl->met_pck_zstd != 1)
7079 ERRMSG("Set MET_PCK_ZSTD to 0 or 1!");
7080#ifndef ZSTD
7081 if (ctl->met_type == 2 && ctl->met_pck_zstd)
7082 ERRMSG("MET_PCK_ZSTD requires MPTRAC to be compiled with ZSTD support!");
7083#endif
7084 const int def_lossy_scale =
7085 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", -1, "0", NULL);
7086 for (int i = 0; i < METVAR; i++) {
7087 char defprec_zfp[LEN] = "7", deftol_zfp[LEN] = "0.0";
7088 char defprec_sz3[LEN] = "6", deftol_sz3[LEN] = "0.0";
7089 if (i == 0) { /* geopotential height */
7090 sprintf(defprec_zfp, "12");
7091 sprintf(defprec_sz3, "11");
7092 } else if (i == 1) { /* temperature */
7093 sprintf(defprec_zfp, "11");
7094 sprintf(defprec_sz3, "7");
7095 } else if (i == 2 || i == 3) { /* horizontal wind */
7096 sprintf(defprec_zfp, "7");
7097 sprintf(defprec_sz3, "7");
7098 } else if (i == 4) { /* vertical wind */
7099 sprintf(defprec_zfp, "6");
7100 sprintf(defprec_sz3, "13");
7101 } else if (i == 5) { /* potential vorticity */
7102 sprintf(defprec_zfp, "7");
7103 sprintf(defprec_sz3, "20");
7104 } else if (i == 6) { /* water vapor */
7105 sprintf(defprec_zfp, "10");
7106 sprintf(defprec_sz3, "18");
7107 } else if (i == 7) { /* ozone */
7108 sprintf(defprec_zfp, "9");
7109 sprintf(defprec_sz3, "10");
7110 } else if (i >= 8 && i <= 11) { /* cloud water fields */
7111 sprintf(defprec_zfp, "6");
7112 sprintf(defprec_sz3, "13");
7113 } else if (i == 12) { /* cloud cover */
7114 sprintf(defprec_zfp, "9");
7115 sprintf(defprec_sz3, "6");
7116 }
7117 ctl->met_zfp_prec[i] =
7118 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", i, defprec_zfp,
7119 NULL);
7120 ctl->met_zfp_tol[i] =
7121 scan_ctl(filename, argc, argv, "MET_ZFP_TOL", i, deftol_zfp, NULL);
7122 ctl->met_sz3_prec[i] =
7123 (int) scan_ctl(filename, argc, argv, "MET_SZ3_PREC", i, defprec_sz3,
7124 NULL);
7125 ctl->met_sz3_tol[i] =
7126 scan_ctl(filename, argc, argv, "MET_SZ3_TOL", i, deftol_sz3, NULL);
7127 char defscale[LEN];
7128 snprintf(defscale, LEN, "%d", def_lossy_scale);
7129 ctl->met_lossy_scale[i] =
7130 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", i, defscale,
7131 NULL);
7132 if (ctl->met_lossy_scale[i] < 0 || ctl->met_lossy_scale[i] > 1)
7133 ERRMSG("Set MET_LOSSY_SCALE to 0 or 1!");
7134 }
7135
7136 /* Scan compression diagnostics file... */
7137 scan_ctl(filename, argc, argv, "MET_COMP_LOGFILE", -1, "-",
7138 ctl->met_comp_logfile);
7139 ctl->met_cms_batch =
7140 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
7141 ctl->met_cms_zstd =
7142 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
7143 ctl->met_cms_nd0x =
7144 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
7145 ctl->met_cms_nd0y =
7146 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
7147 ctl->met_cms_maxlev =
7148 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
7149 for (int i = 0; i < METVAR; i++) {
7150 char defeps[LEN] = "1.0";
7151 if (i == 1 || i == 2 || i == 3)
7152 sprintf(defeps, "0.05");
7153 ctl->met_cms_eps[i] =
7154 scan_ctl(filename, argc, argv, "MET_CMS_EPS", i, defeps, NULL);
7155 }
7156 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
7157 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
7158 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
7159 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
7160 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
7161 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
7162 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
7163 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
7164 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
7165 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
7166 ctl->met_detrend =
7167 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
7168 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
7169 if (ctl->met_np > EP)
7170 ERRMSG("Too many pressure levels!");
7171 ctl->met_press_level_def =
7172 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
7173 NULL);
7174 if (ctl->met_press_level_def >= 0) {
7175 level_definitions(ctl);
7176 } else {
7177 if (ctl->met_np > 0) {
7178 for (int ip = 0; ip < ctl->met_np; ip++)
7179 ctl->met_p[ip] =
7180 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
7181 }
7182 }
7183 ctl->met_nlev =
7184 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
7185 if (ctl->met_nlev > EP)
7186 ERRMSG("Too many model levels!");
7187 for (int ip = 0; ip < ctl->met_nlev; ip++)
7188 ctl->met_lev_hyam[ip] =
7189 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
7190 for (int ip = 0; ip < ctl->met_nlev; ip++)
7191 ctl->met_lev_hybm[ip] =
7192 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
7193 ctl->met_geopot_sx =
7194 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
7195 ctl->met_geopot_sy =
7196 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
7197 ctl->met_relhum =
7198 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
7199 ctl->met_cape =
7200 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
7201 if (ctl->met_cape < 0 || ctl->met_cape > 1)
7202 ERRMSG("Set MET_CAPE to 0 or 1!");
7203 ctl->met_pbl =
7204 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
7205 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
7206 ERRMSG("Set MET_PBL to 0 ... 3!");
7207 ctl->met_pbl_min =
7208 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
7209 ctl->met_pbl_max =
7210 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
7211 ctl->met_tropo =
7212 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
7213 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
7214 ERRMSG("Set MET_TROPO to 0 ... 5!");
7215 ctl->met_tropo_pv =
7216 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
7217 ctl->met_tropo_theta =
7218 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
7219 ctl->met_tropo_spline =
7220 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
7221 ctl->met_dt_out =
7222 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
7223 ctl->met_cache =
7224 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
7225 ctl->met_mpi_share =
7226 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
7227
7228 /* Sorting... */
7229 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
7230
7231 /* Isosurface parameters... */
7232 ctl->isosurf =
7233 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
7234 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
7235
7236 /* Random number generator... */
7237 ctl->rng_type =
7238 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
7239 if (ctl->rng_type < 0 || ctl->rng_type > 2)
7240 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
7241
7242 /* Advection parameters... */
7243 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
7244 if (!(ctl->advect == 1 || ctl->advect == 2 || ctl->advect == 4))
7245 ERRMSG("Set ADVECT to 1, 2, or 4!");
7246
7247 /* Diffusion parameters... */
7248 ctl->diffusion
7249 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
7250 if (ctl->diffusion < 0 || ctl->diffusion > 1)
7251 ERRMSG("Set DIFFUSION to 0 or 1!");
7252 ctl->turb_pbl_scheme =
7253 (int) scan_ctl(filename, argc, argv, "TURB_PBL_SCHEME", -1, "0", NULL);
7254 if (ctl->turb_pbl_scheme < 0 || ctl->turb_pbl_scheme > 1)
7255 ERRMSG("Set TURB_PBL_SCHEME to 0 or 1!");
7256 ctl->turb_dx_pbl =
7257 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
7258 ctl->turb_dx_trop =
7259 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
7260 ctl->turb_dx_strat =
7261 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
7262 ctl->turb_dz_pbl =
7263 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
7264 ctl->turb_dz_trop =
7265 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
7266 ctl->turb_dz_strat =
7267 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
7268 ctl->turb_mesox =
7269 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
7270 ctl->turb_mesoz =
7271 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
7272 ctl->turb_pbl_trans =
7273 scan_ctl(filename, argc, argv, "TURB_PBL_TRANS", -1, "0", NULL);
7274 if (ctl->turb_pbl_trans < 0 || ctl->turb_pbl_trans > 1)
7275 ERRMSG("TURB_PBL_TRANS must be in the range [0, 1]!");
7276
7277 /* Convection... */
7278 ctl->conv_mix_pbl
7279 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
7280 ctl->conv_pbl_trans
7281 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
7282 if (ctl->conv_pbl_trans < 0 || ctl->conv_pbl_trans > 1)
7283 ERRMSG("CONV_PBL_TRANS must be in the range [0, 1]!");
7284 ctl->conv_cape
7285 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
7286 ctl->conv_cin
7287 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
7288 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
7289
7290 /* Boundary conditions... */
7291 ctl->bound_mass =
7292 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
7293 ctl->bound_mass_trend =
7294 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
7295 ctl->bound_vmr =
7296 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
7297 ctl->bound_vmr_trend =
7298 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
7299 ctl->bound_lat0 =
7300 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
7301 ctl->bound_lat1 =
7302 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
7303 ctl->bound_p0 =
7304 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
7305 ctl->bound_p1 =
7306 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
7307 ctl->bound_dps =
7308 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
7309 ctl->bound_dzs =
7310 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
7311 ctl->bound_zetas =
7312 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
7313 ctl->bound_pbl =
7314 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
7315
7316 /* Species parameters... */
7317 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
7318 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
7319 ctl->molmass = 120.907;
7320 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
7321 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
7322 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
7323 ctl->molmass = 137.359;
7324 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
7325 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
7326 } else if (strcasecmp(ctl->species, "CH4") == 0) {
7327 ctl->molmass = 16.043;
7328 ctl->oh_chem_reaction = 2;
7329 ctl->oh_chem[0] = 2.45e-12;
7330 ctl->oh_chem[1] = 1775;
7331 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
7332 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
7333 } else if (strcasecmp(ctl->species, "CO") == 0) {
7334 ctl->molmass = 28.01;
7335 ctl->oh_chem_reaction = 3;
7336 ctl->oh_chem[0] = 6.9e-33;
7337 ctl->oh_chem[1] = 2.1;
7338 ctl->oh_chem[2] = 1.1e-12;
7339 ctl->oh_chem[3] = -1.3;
7340 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
7341 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
7342 } else if (strcasecmp(ctl->species, "CO2") == 0) {
7343 ctl->molmass = 44.009;
7344 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
7345 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
7346 } else if (strcasecmp(ctl->species, "H2O") == 0) {
7347 ctl->molmass = 18.01528;
7348 } else if (strcasecmp(ctl->species, "N2O") == 0) {
7349 ctl->molmass = 44.013;
7350 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
7351 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
7352 } else if (strcasecmp(ctl->species, "NH3") == 0) {
7353 ctl->molmass = 17.031;
7354 ctl->oh_chem_reaction = 2;
7355 ctl->oh_chem[0] = 1.7e-12;
7356 ctl->oh_chem[1] = 710;
7357 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
7358 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
7359 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
7360 ctl->molmass = 63.012;
7361 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
7362 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
7363 } else if (strcasecmp(ctl->species, "NO") == 0) {
7364 ctl->molmass = 30.006;
7365 ctl->oh_chem_reaction = 3;
7366 ctl->oh_chem[0] = 7.1e-31;
7367 ctl->oh_chem[1] = 2.6;
7368 ctl->oh_chem[2] = 3.6e-11;
7369 ctl->oh_chem[3] = 0.1;
7370 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
7371 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
7372 } else if (strcasecmp(ctl->species, "NO2") == 0) {
7373 ctl->molmass = 46.005;
7374 ctl->oh_chem_reaction = 3;
7375 ctl->oh_chem[0] = 1.8e-30;
7376 ctl->oh_chem[1] = 3.0;
7377 ctl->oh_chem[2] = 2.8e-11;
7378 ctl->oh_chem[3] = 0.0;
7379 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
7380 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
7381 } else if (strcasecmp(ctl->species, "O3") == 0) {
7382 ctl->molmass = 47.997;
7383 ctl->oh_chem_reaction = 2;
7384 ctl->oh_chem[0] = 1.7e-12;
7385 ctl->oh_chem[1] = 940;
7386 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
7387 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
7388 } else if (strcasecmp(ctl->species, "SF6") == 0) {
7389 ctl->molmass = 146.048;
7390 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
7391 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
7392 } else if (strcasecmp(ctl->species, "SO2") == 0) {
7393 ctl->molmass = 64.066;
7394 ctl->oh_chem_reaction = 3;
7395 ctl->oh_chem[0] = 2.9e-31;
7396 ctl->oh_chem[1] = 4.1;
7397 ctl->oh_chem[2] = 1.7e-12;
7398 ctl->oh_chem[3] = -0.2;
7399 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = SO2_HENRY_REF;
7400 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = SO2_HENRY_TEMP;
7401 }
7402
7403 /* Molar mass... */
7404 char defstr[LEN];
7405 sprintf(defstr, "%g", ctl->molmass);
7406 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
7407
7408 /* OH chemistry... */
7409 sprintf(defstr, "%d", ctl->oh_chem_reaction);
7410 ctl->oh_chem_reaction =
7411 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
7412 NULL);
7413 for (int ip = 0; ip < 4; ip++) {
7414 sprintf(defstr, "%g", ctl->oh_chem[ip]);
7415 ctl->oh_chem[ip] =
7416 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
7417 }
7418 ctl->oh_chem_beta =
7419 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
7420
7421 /* H2O2 chemistry... */
7422 ctl->h2o2_chem_reaction =
7423 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
7424
7425 /* KPP chemistry... */
7426 ctl->kpp_chem =
7427 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
7428 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
7429
7430 /* First order tracer chemistry... */
7431 ctl->tracer_chem =
7432 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
7433
7434 /* Radioactive decay... */
7435 ctl->radio_decay =
7436 (int) scan_ctl(filename, argc, argv, "RADIO_DECAY", -1, "0", NULL);
7437 ctl->radio_depo =
7438 (int) scan_ctl(filename, argc, argv, "RADIO_DEPO", -1, "0", NULL);
7439 if (ctl->radio_depo && ctl->met_coord_type != 0)
7440 ERRMSG("Radioactive deposition requires a lat/lon meteorological grid!");
7441#ifdef DD
7442 if (ctl->radio_depo)
7443 ERRMSG
7444 ("Radioactive deposition is not supported with domain decomposition!");
7445#endif
7446
7447 /* Wet deposition... */
7448 for (int ip = 0; ip < 2; ip++) {
7449 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
7450 ctl->wet_depo_ic_h[ip] =
7451 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
7452 }
7453 for (int ip = 0; ip < 1; ip++) {
7454 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
7455 ctl->wet_depo_bc_h[ip] =
7456 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
7457 }
7458 ctl->wet_depo_so2_ph =
7459 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
7460 ctl->wet_depo_ic_a =
7461 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
7462 ctl->wet_depo_ic_b =
7463 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
7464 ctl->wet_depo_bc_a =
7465 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
7466 ctl->wet_depo_bc_b =
7467 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
7468 ctl->wet_depo_pre[0] =
7469 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
7470 ctl->wet_depo_pre[1] =
7471 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
7473 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
7475 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
7476
7477 /* Dry deposition... */
7478 ctl->dry_depo_vdep =
7479 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
7480 ctl->dry_depo_dp =
7481 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
7482
7483 /* Climatological data... */
7484 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
7485 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
7486 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
7487 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
7488 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
7489 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
7490 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
7491 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
7492 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
7493 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
7494 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
7495 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
7496 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
7497 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
7498 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
7499 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
7500 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
7501 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
7502 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
7503 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
7504 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
7505 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
7506
7507 /* Mixing... */
7508 ctl->mixing_dt =
7509 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
7510 ctl->mixing_trop =
7511 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
7512 ctl->mixing_strat =
7513 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
7514 ctl->mixing_z0 =
7515 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
7516 ctl->mixing_z1 =
7517 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
7518 ctl->mixing_nz =
7519 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
7520 ctl->mixing_lon0 =
7521 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
7522 ctl->mixing_lon1 =
7523 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
7524 ctl->mixing_nx =
7525 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
7526 ctl->mixing_lat0 =
7527 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
7528 ctl->mixing_lat1 =
7529 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
7530 ctl->mixing_ny =
7531 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
7532 if (ctl->mixing_nx < 1 || ctl->mixing_ny < 1 || ctl->mixing_nz < 1
7533 || ctl->mixing_lon0 >= ctl->mixing_lon1
7534 || ctl->mixing_lat0 >= ctl->mixing_lat1
7535 || ctl->mixing_z0 >= ctl->mixing_z1
7536 || ctl->mixing_lat0 < -90 || ctl->mixing_lat1 > 90)
7537 ERRMSG("Invalid mixing grid!");
7538
7539 /* Chemistry grid... */
7540 ctl->chemgrid_z0 =
7541 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
7542 ctl->chemgrid_z1 =
7543 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
7544 ctl->chemgrid_nz =
7545 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
7546 ctl->chemgrid_lon0 =
7547 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
7548 ctl->chemgrid_lon1 =
7549 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
7550 ctl->chemgrid_nx =
7551 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
7552 ctl->chemgrid_lat0 =
7553 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
7554 ctl->chemgrid_lat1 =
7555 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
7556 ctl->chemgrid_ny =
7557 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
7558 if (ctl->chemgrid_nx < 1 || ctl->chemgrid_ny < 1 || ctl->chemgrid_nz < 1
7559 || ctl->chemgrid_lon0 >= ctl->chemgrid_lon1
7560 || ctl->chemgrid_lat0 >= ctl->chemgrid_lat1
7561 || ctl->chemgrid_z0 >= ctl->chemgrid_z1
7562 || ctl->chemgrid_lat0 < -90 || ctl->chemgrid_lat1 > 90)
7563 ERRMSG("Invalid chemistry grid!");
7564
7565 /* Exponential decay... */
7566 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
7567 ctl->tdec_strat =
7568 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
7569
7570 /* PSC analysis... */
7571 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
7572 ctl->psc_hno3 =
7573 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
7574
7575 /* Output of atmospheric data... */
7576 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
7577 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
7578 ctl->atm_dt_out =
7579 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
7580 ctl->atm_filter =
7581 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
7582 ctl->atm_stride =
7583 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
7584 ctl->atm_type =
7585 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
7586 ctl->atm_type_out =
7587 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
7588 if (ctl->atm_type_out == -1)
7589 ctl->atm_type_out = ctl->atm_type;
7590 ctl->atm_nc_level =
7591 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
7592 for (int iq = 0; iq < ctl->nq; iq++)
7593 ctl->atm_nc_quant[iq] =
7594 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
7595 ctl->obs_type =
7596 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
7597
7598 /* Output of radioactive deposition data... */
7599 scan_ctl(filename, argc, argv, "DEPO_BASENAME", -1, "-",
7600 ctl->depo_basename);
7601 ctl->depo_dt_out =
7602 scan_ctl(filename, argc, argv, "DEPO_DT_OUT", -1, "86400", NULL);
7603 ctl->depo_type =
7604 (int) scan_ctl(filename, argc, argv, "DEPO_TYPE", -1, "0", NULL);
7605
7606 /* Output of CSI data... */
7607 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
7608 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
7609 ctl->csi_dt_out =
7610 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
7611 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
7612 ctl->csi_obsmin =
7613 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
7614 ctl->csi_modmin =
7615 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
7616 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
7617 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
7618 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
7619 ctl->csi_lon0 =
7620 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
7621 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
7622 ctl->csi_nx =
7623 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
7624 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
7625 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
7626 ctl->csi_ny =
7627 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
7628 if (ctl->csi_nx < 1 || ctl->csi_ny < 1 || ctl->csi_nz < 1
7629 || ctl->csi_lon0 >= ctl->csi_lon1
7630 || ctl->csi_lat0 >= ctl->csi_lat1 || ctl->csi_z0 >= ctl->csi_z1
7631 || ctl->csi_lat0 < -90 || ctl->csi_lat1 > 90)
7632 ERRMSG("Invalid CSI grid!");
7633
7634 /* Output of ensemble data... */
7635 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
7636 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
7637 ctl->ens_dt_out =
7638 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
7639
7640 /* Output of grid data... */
7641 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
7642 ctl->grid_basename);
7643 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
7644 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
7645 ctl->grid_dt_out =
7646 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
7647 ctl->grid_sparse =
7648 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
7649 ctl->grid_nc_level =
7650 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
7651 for (int iq = 0; iq < ctl->nq; iq++)
7652 ctl->grid_nc_quant[iq] =
7653 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
7654 ctl->grid_stddev =
7655 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
7656 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
7657 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
7658 ctl->grid_nz =
7659 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
7660 ctl->grid_lon0 =
7661 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
7662 ctl->grid_lon1 =
7663 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
7664 ctl->grid_nx =
7665 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
7666 ctl->grid_lat0 =
7667 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
7668 ctl->grid_lat1 =
7669 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
7670 ctl->grid_ny =
7671 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
7672 ctl->grid_type =
7673 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
7674 if (ctl->grid_nx < 1 || ctl->grid_nx > EX
7675 || ctl->grid_ny < 1 || ctl->grid_ny > EY || ctl->grid_nz < 1)
7676 ERRMSG("Invalid output grid dimensions!");
7677 if (ctl->grid_lon0 >= ctl->grid_lon1
7678 || ctl->grid_lat0 >= ctl->grid_lat1 || ctl->grid_z0 >= ctl->grid_z1
7679 || ctl->grid_lat0 < -90 || ctl->grid_lat1 > 90)
7680 ERRMSG("Invalid output grid boundaries!");
7681 if (ctl->depo_basename[0] != '-'
7682 && (ctl->depo_dt_out <= 0 || ctl->depo_type < 0 || ctl->depo_type > 1))
7683 ERRMSG("Invalid radioactive deposition output settings!");
7684
7685 /* Output of profile data... */
7686 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
7687 ctl->prof_basename);
7688 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
7689 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
7690 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
7691 ctl->prof_nz =
7692 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
7693 ctl->prof_lon0 =
7694 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
7695 ctl->prof_lon1 =
7696 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
7697 ctl->prof_nx =
7698 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
7699 ctl->prof_lat0 =
7700 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
7701 ctl->prof_lat1 =
7702 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
7703 ctl->prof_ny =
7704 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
7705 if (ctl->prof_nx < 1 || ctl->prof_ny < 1 || ctl->prof_nz < 1
7706 || ctl->prof_lon0 >= ctl->prof_lon1
7707 || ctl->prof_lat0 >= ctl->prof_lat1 || ctl->prof_z0 >= ctl->prof_z1
7708 || ctl->prof_lat0 < -90 || ctl->prof_lat1 > 90)
7709 ERRMSG("Invalid profile grid!");
7710
7711 /* Output of sample data... */
7712 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
7713 ctl->sample_basename);
7714 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
7715 ctl->sample_kernel);
7716 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
7717 ctl->sample_obsfile);
7718 ctl->sample_dx =
7719 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
7720 ctl->sample_dz =
7721 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
7722
7723 /* Output of station data... */
7724 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
7725 ctl->stat_basename);
7726 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
7727 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
7728 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
7729 ctl->stat_t0 =
7730 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
7731 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
7732
7733 /* Output of VTK data... */
7734 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
7735 ctl->vtk_dt_out =
7736 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
7737 ctl->vtk_stride =
7738 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
7739 ctl->vtk_scale =
7740 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
7741 ctl->vtk_offset =
7742 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
7743 ctl->vtk_sphere =
7744 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
7745
7746 /* Domain decomposition... */
7747#ifdef DD
7748 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "1", NULL);
7749#else
7750 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
7751#endif
7752
7754 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
7755 (ctl->dd == 1) ? "2" : "1", NULL);
7756 ctl->dd_subdomains_zonal =
7757 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
7758 (ctl->dd == 1) ? "2" : "1", NULL);
7759 ctl->dd_halos_size =
7760 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
7761 ctl->dd_sort_dt =
7762 (double) scan_ctl(filename, argc, argv, "DD_SORT_DT", -1, "1800", NULL);
7763}
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:3342
double scan_ctl(const char *filename, int argc, char *argv[], const char *varname, const int arridx, const char *defvalue, char *value)
Scans a control file or command-line arguments for a specified variable.
Definition: mptrac.c:12462
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:563
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:553
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:573
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:2002
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3426
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2605
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3387
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3354
int qnt_target_subdomain
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2821
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2872
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2638
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3363
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2584
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3550
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3315
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2617
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3357
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2626
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3378
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2593
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3504
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:3015
double stat_r
Search radius around station [km].
Definition: mptrac.h:3510
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3381
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3534
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2983
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2614
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2692
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3453
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3429
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2935
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:3002
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2656
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2731
char species[LEN]
Species.
Definition: mptrac.h:3119
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3372
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3384
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2980
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2608
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3414
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2539
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2635
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2662
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2999
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3489
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2725
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2971
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3405
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2560
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2704
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3516
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3348
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3450
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3375
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2566
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3420
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2689
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2968
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2941
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2536
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3456
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2542
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3459
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3351
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2977
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3360
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2938
double depo_dt_out
DEPO_DT_OUT time interval for radioactive deposition output [s] (default: 86400).
Definition: mptrac.h:3306
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3402
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3462
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2599
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2993
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3468
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2521
double dd_sort_dt
Sorting time interval for the compactification.
Definition: mptrac.h:3553
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:3008
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2734
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2659
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3369
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3513
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3541
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3333
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2917
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2959
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:3245
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3345
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2557
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2548
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3522
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:3080
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3492
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2650
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3399
char met_comp_logfile[LEN]
Filename for per-level compression diagnostics ("-" disables output).
Definition: mptrac.h:2908
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2578
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2698
int met_gp2z
Convert surface geopotential to geopotential height (0=no, 1=yes).
Definition: mptrac.h:2862
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2986
int met_dx
Stride for longitudes.
Definition: mptrac.h:2929
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2846
char depo_basename[LEN]
DEPO_BASENAME for radioactive deposition files (default: disabled with "-").
Definition: mptrac.h:3303
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2710
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:3248
int diffusion
Diffusion switch (0=off, 1=on).
Definition: mptrac.h:3035
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2581
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3531
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2596
double met_zfp_tol[METVAR]
ZFP compression tolerance.
Definition: mptrac.h:2896
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2653
int met_sz3_prec[METVAR]
SZ3 compression precision.
Definition: mptrac.h:2899
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2602
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3477
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2701
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2590
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3498
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3342
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3417
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2545
int depo_type
DEPO_TYPE of deposition files (0=ASCII, 1=netCDF, default: 0).
Definition: mptrac.h:3309
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:3312
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2569
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2629
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3465
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2962
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2587
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3321
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:3242
int met_lz4_accel
LZ4 acceleration factor (>=1, default=8).
Definition: mptrac.h:2887
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3393
int met_vert_coord
Vertical coordinate of input meteo data (0=plev, 1=mlev_p_file, 2=mlev_ab_file, 3=mlev_ab_full,...
Definition: mptrac.h:2859
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3366
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2728
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3507
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2947
double met_cms_eps[METVAR]
cmultiscale compression epsilon.
Definition: mptrac.h:2926
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2641
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2920
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2647
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3423
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2554
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3396
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3486
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3324
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2974
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3318
int met_lossy_scale[METVAR]
Apply levelwise [0,1] scaling before lossy compression (0=off, 1=on).
Definition: mptrac.h:2905
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3483
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2911
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:3293
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2944
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3471
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2623
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2671
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2686
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2965
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3480
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2644
double turb_pbl_trans
Depth of turbulent PBL transition layer (fraction of PBL pressure thickness).
Definition: mptrac.h:3065
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:3296
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3474
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2878
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:3239
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3339
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2914
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2923
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3411
double met_sz3_tol[METVAR]
SZ3 compression tolerance.
Definition: mptrac.h:2902
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3519
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2572
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2875
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:3167
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3528
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2737
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2563
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3336
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2695
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2551
int met_dy
Stride for latitudes.
Definition: mptrac.h:2932
int radio_depo
RADIO_DEPO switch for radionuclide deposition (0=off, 1=on, default: 0).
Definition: mptrac.h:3254
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3544
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2515
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2996
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2611
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2506
int met_zfp_prec[METVAR]
ZFP compression precision.
Definition: mptrac.h:2893
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3495
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3525
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3501
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3547
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2575
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2620
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2632
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3408
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2740
Here is the call graph for this function:

◆ mptrac_read_met()

int mptrac_read_met ( const char *  filename,
const ctl_t ctl,
const clim_t clim,
met_t met,
dd_t dd 
)

Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.

This function reads meteorological data from a file specified by the filename parameter. It supports both NetCDF and binary formats based on the met_type field in the ctl_t structure. The function can also handle parallel processing with MPI, broadcasting the data across ranks if required by the configuration.

Parameters
filenameA constant character pointer representing the name of the file to read the meteorological data from.
ctlA pointer to a ctl_t structure, which holds control parameters including the type of meteorological data, MPI sharing flags, and configuration details.
climA pointer to a clim_t structure, which contains climatological data to be used in the process, if applicable.
metA pointer to a met_t structure that will store the meteorological data read from the file.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.
Returns
Returns an integer, where 1 indicates success.
Note
  • The function logs the action of reading meteorological data, including the file name.
  • It supports MPI parallelization and will share the data across multiple processes if the met_mpi_share flag is set in the control structure.
  • If ctl->met_type is 0, the data is read from a NetCDF file using the read_met_nc function.
  • If ctl->met_type is between 1 and 5, or equals 7 or 8, the data is read from a binary file using the read_met_bin function.
  • If ctl->met_type is 6, the data is read from grib files using the read_met_grib function.
  • If the met_type is not recognized, an error message is generated.
Author
Lars Hoffmann

Definition at line 7767 of file mptrac.c.

7772 {
7773
7774 /* Write info... */
7775 LOG(1, "Read meteo data: %s", filename);
7776
7777 /* Set rank... */
7778 int rank = 0;
7779#ifdef MPI
7780 if (ctl->met_mpi_share)
7781 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
7782#endif
7783
7784 /* Check rank... */
7785 if (!ctl->met_mpi_share || rank == 0) {
7786
7787 /* Read netCDF data... */
7788 if (ctl->met_type == 0) {
7789 if (read_met_nc(filename, ctl, met, dd) != 1)
7790 return 0;
7791 }
7792
7793 /* Read binary data... */
7794 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
7795 || ctl->met_type == 7 || ctl->met_type == 8) {
7796 if (read_met_bin(filename, ctl, met) != 1)
7797 return 0;
7798 }
7799#ifdef ECCODES
7800 /* Read grib data... */
7801 else if (ctl->met_type == 6) {
7802 if (read_met_grib(filename, ctl, met) != 1)
7803 return 0;
7804 }
7805#endif
7806
7807 /* Not implemented... */
7808 else
7809 ERRMSG("MET_TYPE not implemented!");
7810
7811 /* Preprocessing for netCDF and grib files... */
7812 if (ctl->met_type == 0 || ctl->met_type == 6) {
7813
7814 /* Extrapolate data for lower boundary... */
7816
7817 /* Fix polar winds... */
7819
7820 /* Create periodic boundary conditions... */
7821#ifndef DD
7822 read_met_periodic(met);
7823#endif
7824
7825 /* Downsampling... */
7826 read_met_sample(ctl, met);
7827
7828 /* Calculate geopotential heights... */
7829 read_met_geopot(ctl, met);
7830
7831 /* Calculate potential vorticity... */
7832 read_met_pv(met);
7833
7834 /* Calculate boundary layer data... */
7835 read_met_pbl(ctl, met);
7836
7837 /* Calculate tropopause data... */
7838 read_met_tropo(ctl, clim, met);
7839
7840 /* Calculate cloud properties... */
7841 read_met_cloud(met);
7842
7843 /* Calculate convective available potential energy... */
7844 read_met_cape(ctl, clim, met);
7845
7846 /* Calculate total column ozone... */
7847 read_met_ozone(met);
7848
7849 /* Detrending... */
7850 read_met_detrend(ctl, met);
7851
7852 /* Check meteo data and smooth zeta profiles ... */
7853 read_met_monotonize(ctl, met);
7854 }
7855 }
7856
7857 /* Broadcast data via MPI... */
7858#ifdef MPI
7859 if (ctl->met_mpi_share) {
7860
7861 /* Set timer... */
7862 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM");
7863 LOG(2, "Broadcast data on rank %d...", rank);
7864
7865 /* Broadcast... */
7866 broadcast_large_data(met, sizeof(met_t));
7867 }
7868#endif
7869
7870 /* Return success... */
7871 return 1;
7872}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:9535
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:9495
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:12014
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:9331
void read_met_pbl(const ctl_t *ctl, met_t *met)
Computes the planetary boundary layer (PBL) pressure based on meteorological data.
Definition: mptrac.c:11605
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:9388
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:11301
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:11742
int read_met_nc(const char *filename, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads meteorological data from a NetCDF file and processes it.
Definition: mptrac.c:11386
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:11985
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:11865
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:8912
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:11803
void read_met_cape(const ctl_t *ctl, const clim_t *clim, met_t *met)
Calculates Convective Available Potential Energy (CAPE) for each grid point.
Definition: mptrac.c:9211
int read_met_grib(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a grib file and processes it.
void broadcast_large_data(void *data, size_t N)
Broadcasts large data across all processes in an MPI communicator.
Here is the call graph for this function:

◆ mptrac_run_timestep()

void mptrac_run_timestep ( ctl_t ctl,
cache_t cache,
clim_t clim,
met_t **  met0,
met_t **  met1,
atm_t atm,
depo_t depo,
double  t,
dd_t dd 
)

Executes a single timestep of the MPTRAC model simulation.

This function performs all operations required to advance the model simulation by one timestep. It includes updating air parcel positions, applying advection, diffusion, convection, and other processes such as sedimentation, chemistry, and deposition. Each process is conditionally executed based on the control settings provided in the ctl structure.

Parameters
ctlPointer to the control structure containing model parameters and settings.
cachePointer to the cache structure used for intermediate calculations.
climPointer to the climatology structure containing climatological data.
met0Pointer to the current meteorological data structure.
met1Pointer to the next meteorological data structure.
atmPointer to the atmosphere structure containing air parcel data.
depoPointer to cumulative radionuclide ground inventories.
tCurrent simulation time in seconds.
ddMPI information required for the domain decomposition.
Author
Lars Hoffmann

Definition at line 7876 of file mptrac.c.

7885 {
7886
7887 /* Initialize modules... */
7888 if (t == ctl->t_start) {
7889
7890 /* Initialize isosurface data... */
7891 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7892 module_isosurf_init(ctl, cache, *met0, *met1, atm);
7893
7894 /* Initialize advection... */
7895 module_advect_init(ctl, cache, *met0, *met1, atm);
7896
7897 /* Initialize chemistry... */
7898 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
7899 }
7900
7901 /* Set time steps of air parcels... */
7902 module_timesteps(ctl, cache, *met0, atm, t);
7903
7904 /* Sort particles... */
7905 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
7906 module_sort(ctl, *met0, atm);
7907
7908 /* Check positions (initial)... */
7909 module_position(cache, *met0, *met1, atm, 0);
7910
7911 /* Advection... */
7912 if (ctl->advect > 0)
7913 module_advect(ctl, cache, *met0, *met1, atm);
7914
7915 /* Turbulent diffusion... */
7916 if (ctl->diffusion
7917 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
7918 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
7919 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
7920 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
7921
7922 /* Optional PBL-specific diffusion scheme... */
7923 if (ctl->diffusion && ctl->turb_pbl_scheme == 1)
7924 module_diff_pbl(ctl, cache, *met0, *met1, atm);
7925
7926 /* Mesoscale diffusion... */
7927 if (ctl->diffusion && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
7928 module_diff_meso(ctl, cache, *met0, *met1, atm);
7929
7930 /* Convection... */
7931 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
7932 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
7933 module_convection(ctl, cache, *met0, *met1, atm);
7934
7935 /* Sedimentation... */
7936 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
7937 module_sedi(ctl, cache, *met0, *met1, atm);
7938
7939 /* Isosurface... */
7940 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7941 module_isosurf(ctl, cache, *met0, *met1, atm);
7942
7943 /* Check positions (final)... */
7944 module_position(cache, *met0, *met1, atm, 1);
7945
7946 /* Interpolate meteo data... */
7947 if (ctl->met_dt_out > 0
7948 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
7949 module_meteo(ctl, cache, clim, *met0, *met1, atm);
7950
7951 /* Check boundary conditions (initial)... */
7952 if ((ctl->bound_lat0 < ctl->bound_lat1)
7953 && (ctl->bound_p0 > ctl->bound_p1))
7954 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
7955
7956 /* Initialize quantity of total loss rate... */
7957 if (ctl->qnt_loss_rate >= 0) {
7958 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
7959 atm->q[ctl->qnt_loss_rate][ip] = 0;
7960 }
7961 }
7962
7963 /* Decay of particle mass... */
7964 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
7965 module_decay(ctl, cache, clim, atm);
7966
7967 /* Interparcel mixing... */
7968 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
7969 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
7970 module_mixing(ctl, clim, atm, t);
7971
7972 /* Calculate the tracer vmr in the chemistry grid... */
7973 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
7974 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
7975 module_chem_grid(ctl, *met0, *met1, atm, t);
7976
7977 /* OH chemistry... */
7978 if (ctl->oh_chem_reaction != 0)
7979 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
7980
7981 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
7982 if (ctl->h2o2_chem_reaction != 0)
7983 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
7984
7985 /* First-order tracer chemistry... */
7986 if (ctl->tracer_chem)
7987 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
7988
7989 /* Radioactive decay... */
7990 if (ctl->radio_decay)
7991 module_radio_decay(ctl, cache, atm);
7992
7993 /* Domain decomposition... */
7994#ifdef DD
7995 module_dd(t, ctl, cache, dd, atm, met0);
7996#else
7997 (void) dd;
7998#endif
7999
8000 /* Radioactive deposition... */
8001 if (ctl->radio_depo)
8002 module_radio_depo(ctl, cache, *met0, *met1, atm, depo);
8003
8004 /* KPP chemistry... */
8005 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
8006#ifdef KPP
8007 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
8008#else
8009 ERRMSG("Code was compiled without KPP!");
8010#endif
8011 }
8012
8013 /* Wet deposition... */
8014 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
8015 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
8016 module_wet_depo(ctl, cache, *met0, *met1, atm);
8017
8018 /* Dry deposition... */
8019 if (ctl->dry_depo_vdep > 0)
8020 module_dry_depo(ctl, cache, *met0, *met1, atm);
8021
8022 /* Check boundary conditions (final)... */
8023 if ((ctl->bound_lat0 < ctl->bound_lat1)
8024 && (ctl->bound_p0 > ctl->bound_p1))
8025 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
8026}
void module_advect(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Advances particle positions using different advection schemes.
Definition: mptrac.c:3598
void module_meteo(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Update atmospheric properties using meteorological data.
Definition: mptrac.c:5062
void module_decay(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, atm_t *atm)
Simulate exponential decay processes for atmospheric particles.
Definition: mptrac.c:4227
void module_chem_init(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Initializes the chemistry modules by setting atmospheric composition.
Definition: mptrac.c:4058
void module_mixing(const ctl_t *ctl, const clim_t *clim, atm_t *atm, const double t)
Update atmospheric properties through interparcel mixing.
Definition: mptrac.c:5188
void module_isosurf_init(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Initialize the isosurface module based on atmospheric data.
Definition: mptrac.c:4886
void module_wet_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Perform wet deposition calculations for air parcels.
Definition: mptrac.c:6175
void module_chem_grid(const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double tt)
Computes gridded chemical tracer concentrations (volume mixing ratio) from individual air parcel mass...
Definition: mptrac.c:3885
void module_sedi(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate sedimentation of particles in the atmosphere.
Definition: mptrac.c:5879
void module_sort(const ctl_t *ctl, const met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:5907
void module_convection(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Performs convective mixing of atmospheric particles.
Definition: mptrac.c:4102
void module_bound_cond(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Apply boundary conditions to particles based on meteorological and climatological data.
Definition: mptrac.c:3789
void module_advect_init(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Initializes the advection module by setting up pressure fields.
Definition: mptrac.c:3762
void module_position(const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm, const int reflect)
Update the positions and pressure levels of atmospheric particles.
Definition: mptrac.c:5454
void module_radio_decay(const ctl_t *ctl, const cache_t *cache, atm_t *atm)
Apply radioactive decay to atmospheric tracer species.
Definition: mptrac.c:5513
void module_diff_meso(const ctl_t *ctl, cache_t *cache, const met_t *met0, const met_t *met1, atm_t *atm)
Simulate mesoscale diffusion for atmospheric particles.
Definition: mptrac.c:4266
void module_diff_turb(const ctl_t *ctl, cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Applies turbulent diffusion processes to atmospheric particles.
Definition: mptrac.c:4588
void module_timesteps(const ctl_t *ctl, cache_t *cache, const met_t *met0, atm_t *atm, const double t)
Calculate time steps for air parcels based on specified conditions.
Definition: mptrac.c:6019
void module_tracer_chem(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Simulate chemical reactions involving long-lived atmospheric tracers.
Definition: mptrac.c:6097
void module_h2o2_chem(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Perform chemical reactions involving H2O2 within cloud particles.
Definition: mptrac.c:4801
void module_diff_pbl(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Computes particle diffusion within the planetary boundary layer (PBL).
Definition: mptrac.c:4343
void module_isosurf(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Apply the isosurface module to adjust atmospheric properties.
Definition: mptrac.c:4956
void module_oh_chem(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Perform hydroxyl chemistry calculations for atmospheric particles.
Definition: mptrac.c:5370
void module_dry_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate dry deposition of atmospheric particles.
Definition: mptrac.c:4738
void module_radio_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm, depo_t *depo)
Deposit supported radionuclides from air parcels onto the ground grid.
Definition: mptrac.c:5571
void module_kpp_chem(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
KPP chemistry module.
void module_dd(double t, const ctl_t *ctl, cache_t *cache, dd_t *dd, atm_t *atm, met_t **met)
Perform domain decomposition and exchange particles between MPI ranks.
Here is the call graph for this function:

◆ mptrac_update_device()

void mptrac_update_device ( const ctl_t ctl,
const cache_t cache,
const clim_t clim,
met_t **  met0,
met_t **  met1,
const atm_t atm 
)

Updates device memory for specified data structures.

This function updates the GPU memory with the data from the provided host data structures (ctl, cache, clim, atm) using OpenACC directives. It ensures that the host data is transferred to the device for further computation.

Parameters
[in]ctlPointer to the ctl_t structure. If not NULL, the corresponding device memory for ctl is updated.
[in]cachePointer to the cache_t structure. If not NULL, the corresponding device memory for cache is updated.
[in]climPointer to the clim_t structure. If not NULL, the corresponding device memory for clim is updated.
[in]met0Pointer to the first met_t structure. If not NULL, the corresponding device memory for met0 is updated.
[in]met1Pointer to the second met_t structure. If not NULL, the corresponding device memory for met1 is updated.
[in]atmPointer to the atm_t structure. If not NULL, the corresponding device memory for atm is updated.
Note
The function assumes that OpenACC is enabled and uses the #pragma acc update directive for device memory synchronization. Each update operation is wrapped with a timer labeled as "UPDATE_DEVICE" for performance tracking.
Warning
Ensure that the pointers passed to this function are valid and properly initialized before calling this function. Passing invalid or uninitialized pointers may lead to undefined behavior.
Author
Lars Hoffmann

Definition at line 8030 of file mptrac.c.

8036 {
8037
8038 /* Update GPU... */
8039 if (ctl != NULL) {
8040#ifdef _OPENACC
8041 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8042#pragma acc update device(ctl[:1])
8043#endif
8044 }
8045
8046 if (cache != NULL) {
8047#ifdef _OPENACC
8048 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8049#pragma acc update device(cache[:1])
8050#endif
8051 }
8052
8053 if (clim != NULL) {
8054#ifdef _OPENACC
8055 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8056#pragma acc update device(clim[:1])
8057#endif
8058 }
8059
8060 if (met0 != NULL) {
8061#ifdef _OPENACC
8062 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8063 met_t *met0up = *met0;
8064#pragma acc update device(met0up[:1])
8065#endif
8066 }
8067
8068 if (met1 != NULL) {
8069#ifdef _OPENACC
8070 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8071 met_t *met1up = *met1;
8072#pragma acc update device(met1up[:1])
8073#endif
8074 }
8075
8076 if (atm != NULL) {
8077#ifdef _OPENACC
8078 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8079#pragma acc update device(atm[:1])
8080#endif
8081 }
8082}

◆ mptrac_update_host()

void mptrac_update_host ( const ctl_t ctl,
const cache_t cache,
const clim_t clim,
met_t **  met0,
met_t **  met1,
const atm_t atm 
)

Updates host memory for specified data structures.

This function transfers data from the device (GPU) memory back to the host memory for the provided data structures (ctl, cache, clim, atm) using OpenACC directives. It ensures that the latest data from the device is synchronized with the host.

Parameters
[in]ctlPointer to the ctl_t structure. If not NULL, the corresponding host memory for ctl is updated from the device.
[in]cachePointer to the cache_t structure. If not NULL, the corresponding host memory for cache is updated from the device.
[in]climPointer to the clim_t structure. If not NULL, the corresponding host memory for clim is updated from the device.
[in]met0Pointer to the first met_t structure. If not NULL, the corresponding host memory for met0 is updated.
[in]met1Pointer to the second met_t structure. If not NULL, the corresponding host memory for met1 is updated.
[in]atmPointer to the atm_t structure. If not NULL, the corresponding host memory for atm is updated from the device.
Note
The function assumes that OpenACC is enabled and uses the #pragma acc update directive for host memory synchronization. Each update operation is wrapped with a timer labeled as "UPDATE_HOST" for performance tracking.
Warning
Ensure that the pointers passed to this function are valid and properly initialized before calling this function
Author
Lars Hoffmann

Definition at line 8086 of file mptrac.c.

8092 {
8093
8094 /* Update GPU... */
8095 if (ctl != NULL) {
8096#ifdef _OPENACC
8097 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8098#pragma acc update host(ctl[:1])
8099#endif
8100 }
8101
8102 if (cache != NULL) {
8103#ifdef _OPENACC
8104 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8105#pragma acc update host(cache[:1])
8106#endif
8107 }
8108
8109 if (clim != NULL) {
8110#ifdef _OPENACC
8111 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8112#pragma acc update host(clim[:1])
8113#endif
8114 }
8115
8116 if (met0 != NULL) {
8117#ifdef _OPENACC
8118 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8119 met_t *met0up = *met0;
8120#pragma acc update host(met0up[:1])
8121#endif
8122 }
8123
8124 if (met1 != NULL) {
8125#ifdef _OPENACC
8126 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8127 met_t *met1up = *met1;
8128#pragma acc update host(met1up[:1])
8129#endif
8130 }
8131
8132 if (atm != NULL) {
8133#ifdef _OPENACC
8134 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8135#pragma acc update host(atm[:1])
8136#endif
8137 }
8138}

◆ mptrac_write_atm()

void mptrac_write_atm ( const char *  filename,
const ctl_t ctl,
const atm_t atm,
const double  t 
)

Writes air parcel data to a file in various formats.

The mptrac_write_atm function writes the air parcel data stored in the atm structure to a file specified by filename. The format of the output file is determined by the atm_type_out field in the ctl control structure.

Parameters
filenameA string representing the name of the file to write the data to.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.
tThe current time, used for certain output formats.

The function performs the following steps:

  • Sets a timer for the write operation using the SELECT_TIMER macro.
  • Logs the beginning of the write operation with the specified filename.
  • Depending on the atm_type_out value in the ctl structure, writes the data in one of the following formats:
    • ASCII (atm_type_out == 0): Calls write_atm_asc.
    • Binary (atm_type_out == 1): Calls write_atm_bin.
    • netCDF (atm_type_out == 2): Calls write_atm_nc.
    • CLaMS trajectory data (atm_type_out == 3): Calls write_atm_clams_traj.
    • CLaMS position data (atm_type_out == 4): Calls write_atm_clams.
  • If the atm_type_out value is not supported, triggers an error message.
  • Logs various statistics about the atmospheric data, including the number of particles, time range, altitude range, pressure range, longitude range, and latitude range.
  • Logs the range for each quantity specified in the ctl structure.
Author
Lars Hoffmann

Definition at line 8142 of file mptrac.c.

8146 {
8147
8148 /* Set timer... */
8149 SELECT_TIMER("WRITE_ATM", "OUTPUT");
8150
8151 /* Write info... */
8152 LOG(1, "Write atmospheric data: %s", filename);
8153
8154 /* Write ASCII data... */
8155 if (ctl->atm_type_out == 0)
8156 write_atm_asc(filename, ctl, atm, t);
8157
8158 /* Write binary data... */
8159 else if (ctl->atm_type_out == 1)
8160 write_atm_bin(filename, ctl, atm);
8161
8162 /* Write netCDF data... */
8163 else if (ctl->atm_type_out == 2)
8164 write_atm_nc(filename, ctl, atm);
8165
8166 /* Write CLaMS trajectory data... */
8167 else if (ctl->atm_type_out == 3)
8168 write_atm_clams_traj(filename, ctl, atm, t);
8169
8170 /* Write CLaMS pos data... */
8171 else if (ctl->atm_type_out == 4)
8172 write_atm_clams(filename, ctl, atm);
8173
8174 /* Error... */
8175 else
8176 ERRMSG("Atmospheric data type not supported!");
8177
8178 /* Write info... */
8179 double mini, maxi;
8180 LOG(2, "Number of particles: %d", atm->np);
8181 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
8182 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8183 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
8184 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
8185 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
8186 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
8187 LOG(2, "%s range: %g ... %g %s",
8188 ctl->met_coord_type == 0 ? "Longitude" : "X coordinate", mini, maxi,
8189 ctl->met_coord_type == 0 ? "deg" : "m");
8190 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
8191 LOG(2, "%s range: %g ... %g %s",
8192 ctl->met_coord_type == 0 ? "Latitude" : "Y coordinate", mini, maxi,
8193 ctl->met_coord_type == 0 ? "deg" : "m");
8194 for (int iq = 0; iq < ctl->nq; iq++) {
8195 char msg[5 * LEN];
8196 sprintf(msg, "Quantity %s range: %s ... %s %s",
8197 ctl->qnt_name[iq], ctl->qnt_format[iq],
8198 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
8199 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
8200 LOG(2, msg, mini, maxi);
8201 }
8202}
void write_atm_clams_traj(const char *dirname, const ctl_t *ctl, const atm_t *atm, const double t)
Writes CLaMS trajectory data to a NetCDF file.
Definition: mptrac.c:13006
void write_atm_asc(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes air parcel data to an ASCII file or gnuplot.
Definition: mptrac.c:12802
void write_atm_clams(const char *filename, const ctl_t *ctl, const atm_t *atm)
Writes air parcel data to a NetCDF file in the CLaMS format.
Definition: mptrac.c:12950
void write_atm_bin(const char *filename, const ctl_t *ctl, const atm_t *atm)
Writes air parcel data to a binary file.
Definition: mptrac.c:12900
void write_atm_nc(const char *filename, const ctl_t *ctl, const atm_t *atm)
Writes air parcel data to a NetCDF file.
Definition: mptrac.c:13167
Here is the call graph for this function:

◆ mptrac_write_met()

void mptrac_write_met ( const char *  filename,
const ctl_t ctl,
met_t met 
)

Writes meteorological data to a file, supporting multiple formats and compression options.

This function handles writing meteorological data based on the specified control (ctl_t) and meteorological data (met_t) structures. The file format and compression type are determined by the met_type in the control structure. The function supports netCDF, binary output, and various compression methods (ZFP, ZSTD, CMS), while providing error handling for unsupported configurations.

Parameters
filenameA constant character pointer representing the name of the file to write the meteorological data to.
ctlA pointer to a ctl_t structure, which holds the configuration and control parameters for the output, including the type of meteorological data and compression method.
metA pointer to a met_t structure that holds the meteorological data to be written to the file.
Note
  • The function selects a timer for performance profiling or debugging.
  • It logs the action of writing meteorological data, including the file name.
Warning
  • If ctl->met_type is 3, ZFP compression is required, and the function will generate an error if compiled without ZFP support.
  • If ctl->met_type is 4, ZSTD compression is required, and the function will generate an error if compiled without ZSTD support.
  • If ctl->met_type is 5, CMS compression is required, and the function will generate an error if compiled without CMS support.
  • If ctl->met_type is 7, SZ3 compression is required, and the function will generate an error if compiled without SZ3 support.
  • If ctl->met_type is 8, LZ4 compression is required, and the function will generate an error if compiled without LZ4 support.
Note
  • If ctl->met_type is 0, the function writes data in netCDF format via write_met_nc.
  • If ctl->met_type is between 1 and 5, or equals 7 or 8, the function writes data in binary format via write_met_bin.
  • If ctl->met_type is not recognized, an error message is generated.
Author
Lars Hoffmann

Definition at line 8206 of file mptrac.c.

8209 {
8210
8211 /* Set timer... */
8212 SELECT_TIMER("WRITE_MET", "OUTPUT");
8213
8214 /* Write info... */
8215 LOG(1, "Write meteo data: %s", filename);
8216
8217 /* Check compression flags... */
8218#ifndef ZFP
8219 if (ctl->met_type == 3)
8220 ERRMSG("MPTRAC was compiled without ZFP compression!");
8221#endif
8222#ifndef ZSTD
8223 if (ctl->met_type == 4)
8224 ERRMSG("MPTRAC was compiled without ZSTD compression!");
8225#endif
8226#ifndef LZ4
8227 if (ctl->met_type == 8)
8228 ERRMSG("MPTRAC was compiled without LZ4 compression!");
8229#endif
8230#ifndef CMS
8231 if (ctl->met_type == 5)
8232 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
8233#endif
8234#ifndef SZ3
8235 if (ctl->met_type == 7)
8236 ERRMSG("MPTRAC was compiled without SZ3 compression!");
8237#endif
8238
8239 /* Write netCDF data... */
8240 if (ctl->met_type == 0)
8241 write_met_nc(filename, ctl, met);
8242
8243 /* Write binary data... */
8244 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
8245 || ctl->met_type == 7 || ctl->met_type == 8)
8246 write_met_bin(filename, ctl, met);
8247
8248 /* Not implemented... */
8249 else
8250 ERRMSG("MET_TYPE not implemented!");
8251}
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:14468
void write_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data in binary format to a specified file.
Definition: mptrac.c:14216
Here is the call graph for this function:

◆ mptrac_write_output()

void mptrac_write_output ( const char *  dirname,
const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
depo_t depo,
const double  t 
)

Writes various types of output data to files in a specified directory.

The mptrac_write_output function writes various types of output data to files in the directory specified by the dirname parameter. The function takes control parameters (ctl), two meteorological data structures (met0 and met1), an atmospheric data structure (atm), and a time value (t) as input.

Parameters
dirnameA string representing the directory path where output files will be written.
ctlA pointer to a ctl_t structure containing control parameters.
met0A pointer to a met_t structure representing the first set of meteorological data.
met1A pointer to a met_t structure representing the second set of meteorological data.
atmA pointer to an atm_t structure representing atmospheric data.
depoA pointer to the cumulative radionuclide ground inventories.
tA double value representing the time at which the output is being written.

The function performs the following steps:

  • Parses the input time (t) to extract year, month, day, hour, minute, and second.
  • Updates host memory if necessary based on control parameters.
  • Writes atmospheric data to files if specified by control parameters.
  • Writes gridded data to files if specified by control parameters.
  • Writes cumulative radionuclide deposition if specified by control parameters.
  • Writes CSI (Critical Success Index) data to files if specified by control parameters.
  • Writes ensemble data to files if specified by control parameters.
  • Writes profile data to files if specified by control parameters.
  • Writes sample data to files if specified by control parameters.
  • Writes station data to files if specified by control parameters.
  • Writes VTK (Visualization Toolkit) data to files if specified by control parameters.
Note
This function orchestrates the writing of various types of output data to files based on control parameters and the current simulation time.
Author
Lars Hoffmann

Definition at line 8255 of file mptrac.c.

8262 {
8263
8264 char ext[10], filename[2 * LEN];
8265
8266 double r;
8267
8268 int year, mon, day, hour, min, sec;
8269
8270 /* Get time... */
8271 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
8272
8273 /* Update host... */
8274 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
8275 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
8276 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
8277 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
8278 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
8279 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
8280 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
8281
8282 /* Write atmospheric data... */
8283 if (ctl->atm_basename[0] != '-' &&
8284 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
8285 if (ctl->atm_type_out == 0)
8286 sprintf(ext, "tab");
8287 else if (ctl->atm_type_out == 1)
8288 sprintf(ext, "bin");
8289 else if (ctl->atm_type_out >= 2)
8290 sprintf(ext, "nc");
8291 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
8292 dirname, ctl->atm_basename, year, mon, day, hour, min, sec, ext);
8293 mptrac_write_atm(filename, ctl, atm, t);
8294 }
8295
8296 /* Write gridded data... */
8297 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
8298 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
8299 dirname, ctl->grid_basename, year, mon, day, hour, min, sec,
8300 ctl->grid_type == 0 ? "tab" : "nc");
8301 write_grid(filename, ctl, met0, met1, atm, t);
8302 }
8303
8304 /* Write radioactive deposition data... */
8305 if (ctl->depo_basename[0] != '-'
8306 && (fmod(t, ctl->depo_dt_out) == 0 || t == ctl->t_stop)) {
8307#ifdef _OPENACC
8308#pragma acc update host(depo[:1])
8309#endif
8310 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
8311 dirname, ctl->depo_basename, year, mon, day, hour, min, sec,
8312 ctl->depo_type == 0 ? "tab" : "nc");
8313 write_depo(filename, ctl, depo, t);
8314 }
8315
8316 /* Write CSI data... */
8317 if (ctl->csi_basename[0] != '-') {
8318 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
8319 write_csi(filename, ctl, atm, t);
8320 }
8321
8322 /* Write ensemble data... */
8323 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
8324 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.tab",
8325 dirname, ctl->ens_basename, year, mon, day, hour, min, sec);
8326 write_ens(filename, ctl, atm, t);
8327 }
8328
8329 /* Write profile data... */
8330 if (ctl->prof_basename[0] != '-') {
8331 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
8332 write_prof(filename, ctl, met0, met1, atm, t);
8333 }
8334
8335 /* Write sample data... */
8336 if (ctl->sample_basename[0] != '-') {
8337 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
8338 write_sample(filename, ctl, met0, met1, atm, t);
8339 }
8340
8341 /* Write station data... */
8342 if (ctl->stat_basename[0] != '-') {
8343 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
8344 write_station(filename, ctl, atm, t);
8345 }
8346
8347 /* Write VTK data... */
8348 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
8349 static int nvtk;
8350 if (t == ctl->t_start)
8351 nvtk = 0;
8352 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
8353 write_vtk(filename, ctl, atm, t);
8354 }
8355}
void write_depo(const char *filename, const ctl_t *ctl, const depo_t *depo, const double t)
Convert cumulative ground inventories to Bq m^-2 and write them.
Definition: mptrac.c:13603
void mptrac_write_atm(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes air parcel data to a file in various formats.
Definition: mptrac.c:8142
void write_ens(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes ensemble data to a file.
Definition: mptrac.c:13503
void write_prof(const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
Writes profile data to a specified file.
Definition: mptrac.c:14711
void mptrac_update_host(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
Updates host memory for specified data structures.
Definition: mptrac.c:8086
void write_station(const char *filename, const ctl_t *ctl, atm_t *atm, const double t)
Writes station data to a specified file.
Definition: mptrac.c:15111
void write_vtk(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes VTK (Visualization Toolkit) data to a specified file.
Definition: mptrac.c:15200
void write_sample(const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
Writes sample data to a specified file.
Definition: mptrac.c:14946
void write_grid(const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
Writes grid data to a file in ASCII or netCDF format.
Definition: mptrac.c:13780
void write_csi(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes Critical Success Index (CSI) data to a file.
Definition: mptrac.c:13216
Here is the call graph for this function:

◆ nat_temperature()

double nat_temperature ( const double  p,
const double  h2o,
const double  hno3 
)

Calculates the nitric acid trihydrate (NAT) temperature.

This function computes the temperature at which nitric acid trihydrate (NAT) can form given the partial pressures of water vapor and nitric acid in the atmosphere.

Parameters
pThe total atmospheric pressure (in hPa).
h2oThe volume mixing ratio of water vapor (H2O).
hno3The volume mixing ratio of nitric acid (HNO3).
Returns
The NAT temperature (in Kelvin).

This function follows these steps:

  • Ensures the water vapor volume mixing ratio is above a minimum threshold.
  • Converts the volume mixing ratios of H2O and HNO3 to partial pressures.
  • Uses these partial pressures to compute coefficients for the quadratic equation that determines the NAT temperature.
  • Solves the quadratic equation to find the NAT temperature.

The calculations are based on empirical relationships involving logarithms of the partial pressures of H2O and HNO3.

Note
The constants and formulae used are specific to the context of atmospheric chemistry and the formation of NAT.
Author
Lars Hoffmann

Definition at line 8359 of file mptrac.c.

8362 {
8363
8364 /* Check water vapor volume mixing ratio... */
8365 const double h2o_help = MAX(h2o, 0.1e-6);
8366
8367 /* Calculate T_NAT... */
8368 const double p_hno3 = hno3 * p / 1.333224;
8369 const double p_h2o = h2o_help * p / 1.333224;
8370 const double a = 0.009179 - 0.00088 * log10(p_h2o);
8371 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
8372 const double c = -11397.0 / a;
8373 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
8374 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
8375 if (x2 > 0)
8376 tnat = x2;
8377
8378 return tnat;
8379}

◆ pbl_weight()

double pbl_weight ( const ctl_t ctl,
const atm_t atm,
const int  ip,
const double  pbl,
const double  ps 
)

Computes a weighting factor based on planetary boundary layer pressure.

This function calculates a weighting factor that determines the contribution of a pressure level to processes within the planetary boundary layer. The factor is based on the relative position of the pressure within a linear transition range defined by pbl, ps, and TURB_PBL_TRANS, expressed as a fraction of the PBL pressure thickness (ps - pbl).

Parameters
ctlPointer to the control structure containing configuration parameters.
atmPointer to the atmospheric data structure containing pressure levels.
ipIndex of the pressure level in the atmospheric data array.
pblPressure at the planetary boundary layer.
psSurface pressure.
Returns
Weighting factor for the specified pressure level:
  • Returns 1.0 if the pressure is above the upper boundary (p0).
  • Returns 0.0 if the pressure is below the lower boundary (p1).
  • Returns a linearly interpolated value between 1.0 and 0.0 for pressures within the transition range.
Author
Lars Hoffmann

Definition at line 8383 of file mptrac.c.

8388 {
8389
8390 /* Get pressure range... */
8391 const double p1 = pbl - ctl->turb_pbl_trans * (ps - pbl);
8392 const double p0 = pbl;
8393
8394 /* Get weighting factor... */
8395 if (atm->p[ip] > p0)
8396 return 1;
8397 else if (atm->p[ip] < p1)
8398 return 0;
8399 else
8400 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
8401}

◆ read_atm_asc()

int read_atm_asc ( const char *  filename,
const ctl_t ctl,
atm_t atm 
)

Reads air parcel data from an ASCII file and populates the given atmospheric structure.

This function reads air parcel data from an ASCII file and stores the data in the provided atm_t structure. It reads each line of the file, extracts the necessary data fields, and converts the altitude to pressure.

Parameters
filenameThe name of the ASCII file containing the atmospheric data.
ctlA pointer to the control structure (ctl_t) that specifies the number of quantities.
atmA pointer to the atmospheric structure (atm_t) that will be populated with the data.
Returns
Returns 1 on success, and 0 on failure.

This function performs the following steps:

  • Attempts to open the specified file for reading.
  • Logs a warning and returns 0 if the file cannot be opened.
  • Reads each line of the file and extracts data values for time, altitude, longitude, latitude, and other specified quantities.
  • Converts the altitude to pressure.
  • Increments the data point counter.
  • Checks if the number of data points exceeds the maximum allowed (NP) and logs an error message if so.
  • Closes the file after reading all data.
  • Returns 1 to indicate successful data reading.

The function utilizes several macros and helper functions:

  • WARN for logging warnings.
  • ERRMSG for handling error messages.
  • TOK for tokenizing and reading values from the line.
  • P for converting altitude to pressure.
Author
Lars Hoffmann

Definition at line 8405 of file mptrac.c.

8408 {
8409
8410 /* Open file... */
8411 FILE *in;
8412 if (!(in = fopen(filename, "r"))) {
8413 WARN("Cannot open file!");
8414 return 0;
8415 }
8416
8417 /* Read line... */
8418 char line[LEN];
8419 while (fgets(line, LEN, in)) {
8420
8421 /* Read data... */
8422 char *tok;
8423 TOK(line, tok, "%lg", atm->time[atm->np]);
8424 TOK(NULL, tok, "%lg", atm->p[atm->np]);
8425 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
8426 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
8427 for (int iq = 0; iq < ctl->nq; iq++)
8428 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
8429
8430 /* Convert altitude to pressure... */
8431 atm->p[atm->np] = P(atm->p[atm->np]);
8432
8433 /* Increment data point counter... */
8434 if ((++atm->np) > NP)
8435 ERRMSG("Too many data points!");
8436 }
8437
8438 /* Close file... */
8439 fclose(in);
8440
8441 /* Return success... */
8442 return 1;
8443}
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:2173

◆ read_atm_bin()

int read_atm_bin ( const char *  filename,
const ctl_t ctl,
atm_t atm 
)

Reads air parcel data from a binary file and populates the given atmospheric structure.

This function reads air parcel data from a binary file and stores the data in the provided atm_t structure. It checks the version of the binary data, reads the data values, and verifies the integrity of the data read.

Parameters
filenameThe name of the binary file containing the atmospheric data.
ctlA pointer to the control structure (ctl_t) that specifies the number of quantities.
atmA pointer to the atmospheric structure (atm_t) that will be populated with the data.
Returns
Returns 1 on success, and 0 on failure.

This function performs the following steps:

  • Attempts to open the specified file for reading.
  • Returns 0 if the file cannot be opened.
  • Checks the version of the binary data and logs an error message if the version is incorrect.
  • Reads the number of data points (np).
  • Reads the data arrays for time, pressure, longitude, latitude, and other specified quantities.
  • Checks a final flag to ensure the data was read correctly.
  • Logs an error message if the final flag is incorrect.
  • Closes the file after reading all data.
  • Returns 1 to indicate successful data reading.

The function utilizes several macros and helper functions:

  • ERRMSG for handling error messages.
  • FREAD for reading data from the binary file.
Author
Lars Hoffmann

Definition at line 8447 of file mptrac.c.

8450 {
8451
8452 /* Open file... */
8453 FILE *in;
8454 if (!(in = fopen(filename, "r")))
8455 return 0;
8456
8457 /* Check version of binary data... */
8458 int version;
8459 FREAD(&version, int,
8460 1,
8461 in);
8462 if (version != 100)
8463 ERRMSG("Wrong version of binary data!");
8464
8465 /* Read data... */
8466 FREAD(&atm->np, int,
8467 1,
8468 in);
8469 FREAD(atm->time, double,
8470 (size_t) atm->np,
8471 in);
8472 FREAD(atm->p, double,
8473 (size_t) atm->np,
8474 in);
8475 FREAD(atm->lon, double,
8476 (size_t) atm->np,
8477 in);
8478 FREAD(atm->lat, double,
8479 (size_t) atm->np,
8480 in);
8481 for (int iq = 0; iq < ctl->nq; iq++)
8482 FREAD(atm->q[iq], double,
8483 (size_t) atm->np,
8484 in);
8485
8486 /* Read final flag... */
8487 int final;
8488 FREAD(&final, int,
8489 1,
8490 in);
8491 if (final != 999)
8492 ERRMSG("Error while reading binary data!");
8493
8494 /* Close file... */
8495 fclose(in);
8496
8497 /* Return success... */
8498 return 1;
8499}

◆ read_atm_clams()

int read_atm_clams ( const char *  filename,
const ctl_t ctl,
atm_t atm 
)

Reads atmospheric data from a CLAMS NetCDF file.

This function opens a NetCDF file, reads various atmospheric parameters, and stores them in the provided atm_t structure. It handles both zeta and pressure coordinate systems depending on the control settings.

Parameters
[in]filenamePath to the NetCDF file containing atmospheric data.
[in]ctlPointer to the control structure containing configuration settings.
[out]atmPointer to the atmospheric data structure where the data will be stored.
Returns
Returns 1 on success, 0 on failure.
  • Opens the NetCDF file in read-only mode.
  • Retrieves the number of particles (NPARTS).
  • Reads initial time (TIME_INIT) or falls back to time if unavailable.
  • Depending on ctl->advect_vert_coord, reads ZETA and optionally PRESS, or reads PRESS_INIT with fallback to PRESS.
  • Reads longitude (LON) and latitude (LAT).
  • Closes the NetCDF file before returning.
Author
Jan Clemens

Definition at line 8503 of file mptrac.c.

8506 {
8507
8508 if (ctl->met_coord_type != 0)
8509 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
8510
8511 int ncid, varid;
8512
8513 /* Open file... */
8514 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8515 return 0;
8516
8517 /* Get dimensions... */
8518 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
8519
8520 /* Get time... */
8521 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
8522 NC(nc_get_var_double(ncid, varid, atm->time));
8523 } else {
8524 WARN("TIME_INIT not found use time instead!");
8525 double time_init;
8526 NC_GET_DOUBLE("time", &time_init, 1);
8527 for (int ip = 0; ip < atm->np; ip++) {
8528 atm->time[ip] = time_init;
8529 }
8530 }
8531
8532 /* Read zeta coordinate, pressure is optional... */
8533 if (ctl->advect_vert_coord == 1) {
8534 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
8535 NC_GET_DOUBLE("PRESS", atm->p, 0);
8536 }
8537
8538 /* Read pressure, zeta coordinate is optional... */
8539 else {
8540 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
8541 NC(nc_get_var_double(ncid, varid, atm->p));
8542 } else {
8543 WARN("PRESS_INIT not found use PRESS instead!");
8544 nc_inq_varid(ncid, "PRESS", &varid);
8545 NC(nc_get_var_double(ncid, varid, atm->p));
8546 }
8547 }
8548
8549 /* Read further quantities if requested... */
8550 for (int iq = 0; iq < ctl->nq; iq++)
8551 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8552
8553 /* Read longitude and latitude... */
8554 NC_GET_DOUBLE("LON", atm->lon, 1);
8555 NC_GET_DOUBLE("LAT", atm->lat, 1);
8556
8557 /* Close file... */
8558 NC(nc_close(ncid));
8559
8560 /* Return success... */
8561 return 1;
8562}
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1507
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1566
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1596

◆ read_atm_nc()

int read_atm_nc ( const char *  filename,
const ctl_t ctl,
atm_t atm 
)

Reads air parcel data from a generic netCDF file and populates the given atmospheric structure.

This function reads air parcel data from a netCDF file and stores the data in the provided atm_t structure. It retrieves the dimensions, geolocations (time, pressure, longitude, latitude), and specified variables from the file.

Parameters
filenameThe name of the netCDF file containing the atmospheric data.
ctlA pointer to the control structure (ctl_t) that specifies the number of quantities and their names.
atmA pointer to the atmospheric structure (atm_t) that will be populated with the data.
Returns
Returns 1 on success, and 0 on failure.

This function performs the following steps:

  • Attempts to open the specified netCDF file for reading.
  • Returns 0 if the file cannot be opened.
  • Retrieves the number of observations (np) from the "obs" dimension.
  • Reads the geolocation data arrays for time, pressure, longitude, and latitude.
  • Reads the specified variables into the corresponding arrays in the atm_t structure.
  • Closes the netCDF file after reading all data.
  • Returns 1 to indicate successful data reading.

The function utilizes several macros and helper functions:

  • NC_INQ_DIM for inquiring about dimensions in the netCDF file.
  • NC_GET_DOUBLE for reading double values from the netCDF file.
  • NC for checking netCDF function return values.
Author
Lars Hoffmann

Definition at line 8566 of file mptrac.c.

8569 {
8570
8571 int ncid, varid;
8572
8573 /* Open file... */
8574 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8575 return 0;
8576
8577 /* Get dimensions... */
8578 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
8579
8580 /* Read geolocations... */
8581 NC_GET_DOUBLE("time", atm->time, 1);
8582 NC_GET_DOUBLE("press", atm->p, 1);
8583 NC_GET_DOUBLE("lon", atm->lon, 1);
8584 NC_GET_DOUBLE("lat", atm->lat, 1);
8585
8586 /* Read variables... */
8587 for (int iq = 0; iq < ctl->nq; iq++)
8588 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8589
8590 /* Close file... */
8591 NC(nc_close(ncid));
8592
8593 /* Return success... */
8594 return 1;
8595}

◆ read_clim_photo()

void read_clim_photo ( const char *  filename,
clim_photo_t photo 
)

Reads photolysis rates from a NetCDF file and populates the given photolysis structure.

This function opens a NetCDF file specified by the filename, reads various dimensions and data related to photolysis rates, and stores this data in the provided clim_photo_t structure. It includes checks for data consistency and logs detailed information about the loaded data.

Parameters
filenameA string containing the path to the NetCDF file containing photolysis rate data.
photoA pointer to the photolysis structure (clim_photo_t) that will be populated with the data.

The function performs the following steps:

  • Logs the initiation of reading photolysis rates.
  • Opens the NetCDF file in read-only mode.
  • Reads pressure data and checks for descending order.
  • Reads total column ozone data and checks for ascending order.
  • Reads solar zenith angle data and checks for ascending order.
  • Allocates memory for temporary arrays to hold the data.
  • Reads various photolysis rates (e.g., J_N2O, J_CCl4, J_CFC-11, J_CFC-12, J_O2, J_O3b, J_O3a, J_H2O2, J_H2O) and stores them in the clim_photo_t structure.
  • Frees the allocated memory for temporary arrays.
  • Closes the NetCDF file.
  • Logs detailed information about the loaded data, including pressure levels, solar zenith angles, and photolysis rates.
Author
Mingzhao Liu

Definition at line 8599 of file mptrac.c.

8601 {
8602
8603 int ncid, varid;
8604
8605 /* Write info... */
8606 LOG(1, "Read photolysis rates: %s", filename);
8607
8608 /* Open netCDF file... */
8609 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8610 WARN("Photolysis rate data are missing!");
8611 return;
8612 }
8613
8614 /* Read pressure data... */
8615 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
8616 NC_GET_DOUBLE("press", photo->p, 1);
8617 if (photo->p[0] < photo->p[1])
8618 ERRMSG("Pressure data are not descending!");
8619
8620 /* Read total column ozone data... */
8621 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
8622 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
8623 if (photo->o3c[0] > photo->o3c[1])
8624 ERRMSG("Total column ozone data are not ascending!");
8625
8626 /* Read solar zenith angle data... */
8627 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
8628 NC_GET_DOUBLE("sza", photo->sza, 1);
8629 if (photo->sza[0] > photo->sza[1])
8630 ERRMSG("Solar zenith angle data are not ascending!");
8631
8632 /* Read data... */
8633 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
8634 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
8635 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
8636 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
8637 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
8638 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
8639 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
8640 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
8641 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
8642
8643 /* Close netCDF file... */
8644 NC(nc_close(ncid));
8645
8646 /* Write info... */
8647 LOG(2, "Number of pressure levels: %d", photo->np);
8648 LOG(2, "Altitude levels: %g, %g ... %g km",
8649 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
8650 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8651 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
8652 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
8653 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
8654 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
8655 RAD2DEG(photo->sza[photo->nsza - 1]));
8656 LOG(2, "Number of total column ozone values: %d", photo->no3c);
8657 LOG(2, "Total column ozone: %g, %g ... %g DU",
8658 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
8659 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
8660 photo->n2o[0][0][0], photo->n2o[1][0][0],
8661 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8662 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
8663 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
8664 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8665 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
8666 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
8667 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8668 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
8669 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
8670 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8671 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
8672 photo->o2[0][0][0], photo->o2[1][0][0],
8673 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8674 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
8675 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
8676 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8677 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
8678 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
8679 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8680 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
8681 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
8682 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8683 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
8684 photo->h2o[0][0][0], photo->h2o[1][0][0],
8685 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8686}
void read_clim_photo_help(const int ncid, const char *varname, const clim_photo_t *photo, double var[CP][CSZA][CO3])
Reads a 3D climatological photochemistry variable from a NetCDF file.
Definition: mptrac.c:8690
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:608
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:603
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:613
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3715
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3712
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3721
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3724
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3718
Here is the call graph for this function:

◆ read_clim_photo_help()

void read_clim_photo_help ( const int  ncid,
const char *  varname,
const clim_photo_t photo,
double  var[CP][CSZA][CO3] 
)

Reads a 3D climatological photochemistry variable from a NetCDF file.

This function reads a variable from a NetCDF file into a 3D array based on the dimensions provided by the clim_photo_t structure.

Parameters
[in]ncidNetCDF file ID.
[in]varnameName of the variable to read from the NetCDF file.
[in]photoPointer to a structure defining the data dimensions (np, nsza, no3c).
[out]var3D array to store the read data, with dimensions [CP][CSZA][CO3].
Note
Allocates temporary memory for reading and copies data into the provided array. The memory is freed after the data is copied.
Author
Lars Hoffmann

Definition at line 8690 of file mptrac.c.

8694 {
8695
8696 /* Allocate... */
8697 double *help;
8698 ALLOC(help, double,
8699 photo->np * photo->nsza * photo->no3c);
8700
8701 /* Read variable... */
8702 int varid;
8703 NC_GET_DOUBLE(varname, help, 1);
8704
8705 /* Copy data... */
8706 for (int ip = 0; ip < photo->np; ip++)
8707 for (int is = 0; is < photo->nsza; is++)
8708 for (int io = 0; io < photo->no3c; io++)
8709 var[ip][is][io] =
8710 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
8711
8712 /* Free... */
8713 free(help);
8714}

◆ read_clim_ts()

int read_clim_ts ( const char *  filename,
clim_ts_t ts 
)

Reads a climatological time series from a file and populates the given time series structure.

This function reads time and volume mixing ratio (VMR) data from a specified file, processes the data, and stores it in the provided clim_ts_t structure. It also includes checks for data consistency and logs detailed information about the loaded data.

Parameters
filenameA string containing the path to the file containing the climatological time series data.
tsA pointer to the time series structure (clim_ts_t) that will be populated with the data.
Returns
Returns 1 on success, and 0 on failure (e.g., if the file cannot be opened or data is invalid).

The function performs the following steps:

  • Logs the initiation of reading the climatological time series.
  • Opens the file for reading.
  • Reads time and VMR data from the file, converting years to seconds.
  • Checks for ascending order of time data and ensures the number of data points does not exceed the limit.
  • Closes the file after reading.
  • Checks if there are enough data points.
  • Logs detailed information about the loaded data, including the number of time steps and the range of VMR values.
Author
Lars Hoffmann

Definition at line 8718 of file mptrac.c.

8720 {
8721
8722 /* Write info... */
8723 LOG(1, "Read climatological time series: %s", filename);
8724
8725 /* Open file... */
8726 FILE *in;
8727 if (!(in = fopen(filename, "r"))) {
8728 WARN("Cannot open file!");
8729 return 0;
8730 }
8731
8732 /* Read data... */
8733 char line[LEN];
8734 int nh = 0;
8735 while (fgets(line, LEN, in))
8736 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
8737
8738 /* Convert years to seconds... */
8739 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
8740
8741 /* Check data... */
8742 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
8743 ERRMSG("Time series must be ascending!");
8744
8745 /* Count time steps... */
8746 if ((++nh) >= CTS)
8747 ERRMSG("Too many data points!");
8748 }
8749
8750 /* Close file... */
8751 fclose(in);
8752
8753 /* Check number of data points... */
8754 ts->ntime = nh;
8755 if (nh < 2)
8756 ERRMSG("Not enough data points!");
8757
8758 /* Write info... */
8759 LOG(2, "Number of time steps: %d", ts->ntime);
8760 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
8761 ts->time[nh - 1]);
8762 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
8763 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
8764 (size_t) nh));
8765
8766 /* Exit success... */
8767 return 1;
8768}
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:623

◆ read_clim_zm()

void read_clim_zm ( const char *  filename,
const char *  varname,
clim_zm_t zm 
)

Reads zonally averaged climatological data from a netCDF file and populates the given structure.

This function reads data from a specified netCDF file, including pressure levels, latitudes, and volume mixing ratios (VMR) for a specified variable. It performs necessary checks and logs detailed information about the loaded data.

Parameters
filenameA string containing the path to the netCDF file.
varnameA string containing the name of the variable to be read from the netCDF file.
zmA pointer to the structure (clim_zm_t) that will be populated with the data.

The function performs the following steps:

  • Logs the initiation of reading the specified data.
  • Opens the netCDF file for reading.
  • Reads pressure level data and checks for descending order.
  • Reads latitude data and checks for ascending order.
  • Sets the time data for monthly means.
  • Checks the number of time steps.
  • Reads the specified variable data from the file.
  • Fixes any gaps in the data by interpolating from valid values.
  • Logs detailed information about the loaded data, including the number of time steps, pressure levels, latitude values, and the range of the variable's volume mixing ratios.
Author
Lars Hoffmann

Definition at line 8772 of file mptrac.c.

8775 {
8776
8777 int ncid, varid, it, iy, iz, iz2, nt;
8778
8779 double *help, varmin = 1e99, varmax = -1e99;
8780
8781 /* Write info... */
8782 LOG(1, "Read %s data: %s", varname, filename);
8783
8784 /* Open netCDF file... */
8785 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8786 WARN("%s climatology data are missing!", varname);
8787 return;
8788 }
8789
8790 /* Read pressure data... */
8791 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
8792 NC_GET_DOUBLE("press", zm->p, 1);
8793 if (zm->p[0] < zm->p[1])
8794 ERRMSG("Pressure data are not descending!");
8795
8796 /* Read latitudes... */
8797 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
8798 NC_GET_DOUBLE("lat", zm->lat, 1);
8799 if (zm->lat[0] > zm->lat[1])
8800 ERRMSG("Latitude data are not ascending!");
8801
8802 /* Set time data (for monthly means)... */
8803 zm->ntime = 12;
8804 zm->time[0] = 1209600.00;
8805 zm->time[1] = 3888000.00;
8806 zm->time[2] = 6393600.00;
8807 zm->time[3] = 9072000.00;
8808 zm->time[4] = 11664000.00;
8809 zm->time[5] = 14342400.00;
8810 zm->time[6] = 16934400.00;
8811 zm->time[7] = 19612800.00;
8812 zm->time[8] = 22291200.00;
8813 zm->time[9] = 24883200.00;
8814 zm->time[10] = 27561600.00;
8815 zm->time[11] = 30153600.00;
8816
8817 /* Check number of timesteps... */
8818 NC_INQ_DIM("time", &nt, 12, 12, 1);
8819
8820 /* Read data... */
8821 ALLOC(help, double,
8822 zm->nlat * zm->np * zm->ntime);
8823 NC_GET_DOUBLE(varname, help, 1);
8824 for (it = 0; it < zm->ntime; it++)
8825 for (iz = 0; iz < zm->np; iz++)
8826 for (iy = 0; iy < zm->nlat; iy++)
8827 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
8828 free(help);
8829
8830 /* Fix data gaps... */
8831 for (it = 0; it < zm->ntime; it++)
8832 for (iy = 0; iy < zm->nlat; iy++)
8833 for (iz = 0; iz < zm->np; iz++) {
8834 if (zm->vmr[it][iz][iy] < 0) {
8835 for (iz2 = 0; iz2 < zm->np; iz2++)
8836 if (zm->vmr[it][iz2][iy] >= 0) {
8837 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8838 break;
8839 }
8840 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
8841 if (zm->vmr[it][iz2][iy] >= 0) {
8842 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8843 break;
8844 }
8845 }
8846 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
8847 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
8848 }
8849
8850 /* Close netCDF file... */
8851 NC(nc_close(ncid));
8852
8853 /* Write info... */
8854 LOG(2, "Number of time steps: %d", zm->ntime);
8855 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
8856 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
8857 LOG(2, "Number of pressure levels: %d", zm->np);
8858 LOG(2, "Altitude levels: %g, %g ... %g km",
8859 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
8860 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
8861 zm->p[1], zm->p[zm->np - 1]);
8862 LOG(2, "Number of latitudes: %d", zm->nlat);
8863 LOG(2, "Latitudes: %g, %g ... %g deg",
8864 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
8865 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
8866 varmax);
8867}
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:598

◆ read_kernel()

void read_kernel ( const char *  filename,
double  kz[EP],
double  kw[EP],
int *  nk 
)

Reads kernel function data from a file and populates the provided arrays.

This function reads kernel function data from a specified file, populating the provided arrays kz and kw with the parsed data. It also updates the variable pointed to by nk with the number of data points read. The function ensures that the height levels are in ascending order and performs checks for the number of height levels read.

Parameters
filenameA string containing the path to the file containing kernel function data.
kzA double array to store the height levels of the kernel function.
kwA double array to store the weights corresponding to the height levels.
nkA pointer to an integer variable representing the number of data points read.

The function performs the following steps:

  • Logs information indicating the kernel function file being read.
  • Attempts to open the specified file for reading.
  • Reads data from the file line by line, parsing height levels and weights.
  • Checks that the height levels are in ascending order and that the number of data points does not exceed the defined maximum.
  • Closes the file after reading.
  • Updates the value of nk with the number of data points read.
  • Normalizes the kernel function weights by dividing each weight by the maximum weight.
Author
Lars Hoffmann

Definition at line 8871 of file mptrac.c.

8875 {
8876
8877 /* Write info... */
8878 LOG(1, "Read kernel function: %s", filename);
8879
8880 /* Open file... */
8881 FILE *in;
8882 if (!(in = fopen(filename, "r")))
8883 ERRMSG("Cannot open file!");
8884
8885 /* Read data... */
8886 char line[LEN];
8887 int n = 0;
8888 while (fgets(line, LEN, in))
8889 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
8890 if (n > 0 && kz[n] < kz[n - 1])
8891 ERRMSG("Height levels must be ascending!");
8892 if ((++n) >= EP)
8893 ERRMSG("Too many height levels!");
8894 }
8895
8896 /* Close file... */
8897 fclose(in);
8898
8899 /* Check number of data points... */
8900 *nk = n;
8901 if (n < 2)
8902 ERRMSG("Not enough height levels!");
8903
8904 /* Normalize kernel function... */
8905 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
8906 for (int iz = 0; iz < n; iz++)
8907 kw[iz] /= kmax;
8908}

◆ read_met_bin()

int read_met_bin ( const char *  filename,
const ctl_t ctl,
met_t met 
)

Reads meteorological data from a binary file.

This function reads meteorological data from a binary file and populates the provided met_t structure with the data. It checks the binary file's format version and met_type, ensuring compatibility with the control structure (ctl_t). The function reads time, grid, surface data, and multi-level data, and supports different binary file versions.

Parameters
filenameA constant character pointer representing the name of the binary file to read the meteorological data from.
ctlA pointer to a ctl_t structure that holds control parameters such as the expected met_type and other configuration options.
metA pointer to a met_t structure that will store the meteorological data read from the binary file.
Note
  • The function logs the progress and details of the read operation, such as time, number of longitudes, latitudes, levels, and various meteorological variables.
  • It uses the FREAD macro for safe binary reading operations, which checks the integrity of the read operation.
  • The function reads and verifies the met_type and binary file version to ensure compatibility.
  • Supported binary file versions include 100, 101, and 102, each of which may include additional variables (e.g., LSM, SST, RWC, SWC, and CC).
Warning
  • The function will raise an error if the met_type in the file does not match the ctl->met_type.
  • It will raise an error if the binary file version is not supported.
  • If the dimensions of the data (e.g., number of longitudes, latitudes, or levels) are outside the expected range, an error will be raised.
Author
Lars Hoffmann

Definition at line 8912 of file mptrac.c.

8915 {
8916
8917 FILE *in;
8918
8919 double r;
8920
8921 int year, mon, day, hour, min, sec;
8922
8923 /* Set timer... */
8924 SELECT_TIMER("READ_MET_BIN", "INPUT");
8925
8926 /* Open file... */
8927 if (!(in = fopen(filename, "r"))) {
8928 WARN("Cannot open file!");
8929 return 0;
8930 }
8931
8932 /* Check type of binary data... */
8933 int met_type;
8934 FREAD(&met_type, int,
8935 1,
8936 in);
8937 if (met_type != ctl->met_type)
8938 ERRMSG("Wrong MET_TYPE of binary data!");
8939
8940 /* Check version of binary data... */
8941 int version;
8942 FREAD(&version, int,
8943 1,
8944 in);
8945 if (version != 104)
8946 ERRMSG("Wrong version of binary data!");
8947
8948 /* Read time... */
8949 FREAD(&met->time, double,
8950 1,
8951 in);
8952 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8953 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8954 met->time, year, mon, day, hour, min);
8955 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8956 || day < 1 || day > 31 || hour < 0 || hour > 23)
8957 ERRMSG("Error while reading time!");
8958
8959 /* Read dimensions... */
8960 met->coord_type = ctl->met_coord_type;
8961
8962 FREAD(&met->nx, int,
8963 1,
8964 in);
8965 LOG(2, "Number of %s: %d",
8966 (met->coord_type == 0) ? "longitudes" : "x coordinates", met->nx);
8967 if (met->nx < 2 || met->nx > EX)
8968 ERRMSG(met->coord_type == 0
8969 ? "Number of longitudes out of range!"
8970 : "Number of x coordinates out of range!");
8971
8972 FREAD(&met->ny, int,
8973 1,
8974 in);
8975 LOG(2, "Number of %s: %d",
8976 (met->coord_type == 0) ? "latitudes" : "y coordinates", met->ny);
8977 if (met->ny < 2 || met->ny > EY)
8978 ERRMSG(met->coord_type == 0
8979 ? "Number of latitudes out of range!"
8980 : "Number of y coordinates out of range!");
8981
8982 FREAD(&met->np, int,
8983 1,
8984 in);
8985 LOG(2, "Number of levels: %d", met->np);
8986 if (met->np < 2 || met->np > EP)
8987 ERRMSG("Number of levels out of range!");
8988
8989 /* Read grid... */
8990 FREAD(met->lon, double,
8991 (size_t) met->nx,
8992 in);
8993 LOG(2, "%s: %g, %g ... %g %s",
8994 met->coord_type == 0 ? "Longitudes" : "X coordinates",
8995 met->lon[0], met->lon[1], met->lon[met->nx - 1],
8996 met->coord_type == 0 ? "deg" : "m");
8997
8998 FREAD(met->lat, double,
8999 (size_t) met->ny,
9000 in);
9001 LOG(2, "%s: %g, %g ... %g %s",
9002 met->coord_type == 0 ? "Latitudes" : "Y coordinates",
9003 met->lat[0], met->lat[1], met->lat[met->ny - 1],
9004 met->coord_type == 0 ? "deg" : "m");
9005
9006 FREAD(met->p, double,
9007 (size_t) met->np,
9008 in);
9009 LOG(2, "Altitude levels: %g, %g ... %g km",
9010 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
9011 LOG(2, "Pressure levels: %g, %g ... %g hPa",
9012 met->p[0], met->p[1], met->p[met->np - 1]);
9013
9014 /* Read surface data... */
9015 read_met_bin_2d(in, met, met->ps, "PS");
9016 read_met_bin_2d(in, met, met->ts, "TS");
9017 read_met_bin_2d(in, met, met->zs, "ZS");
9018 read_met_bin_2d(in, met, met->us, "US");
9019 read_met_bin_2d(in, met, met->vs, "VS");
9020 read_met_bin_2d(in, met, met->ess, "ESS");
9021 read_met_bin_2d(in, met, met->nss, "NSS");
9022 read_met_bin_2d(in, met, met->shf, "SHF");
9023 read_met_bin_2d(in, met, met->lsm, "LSM");
9024 read_met_bin_2d(in, met, met->sst, "SST");
9025 read_met_bin_2d(in, met, met->pbl, "PBL");
9026 read_met_bin_2d(in, met, met->pt, "PT");
9027 read_met_bin_2d(in, met, met->tt, "TT");
9028 read_met_bin_2d(in, met, met->zt, "ZT");
9029 read_met_bin_2d(in, met, met->h2ot, "H2OT");
9030 read_met_bin_2d(in, met, met->pct, "PCT");
9031 read_met_bin_2d(in, met, met->pcb, "PCB");
9032 read_met_bin_2d(in, met, met->cl, "CL");
9033 read_met_bin_2d(in, met, met->plcl, "PLCL");
9034 read_met_bin_2d(in, met, met->plfc, "PLFC");
9035 read_met_bin_2d(in, met, met->pel, "PEL");
9036 read_met_bin_2d(in, met, met->cape, "CAPE");
9037 read_met_bin_2d(in, met, met->cin, "CIN");
9038 read_met_bin_2d(in, met, met->o3c, "O3C");
9039
9040 /* Read level data... */
9041 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
9042 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
9043 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
9044 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
9045 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
9046 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
9047 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
9048 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
9049 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
9050 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
9051 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
9052 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
9053 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
9054
9055 /* Read final flag... */
9056 int final;
9057 FREAD(&final, int,
9058 1,
9059 in);
9060 if (final != 999)
9061 ERRMSG("Error while reading binary data!");
9062
9063 /* Close file... */
9064 fclose(in);
9065
9066 /* Return success... */
9067 return 1;
9068}
void read_met_bin_2d(FILE *in, const met_t *met, float var[EX][EY], const char *varname)
Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array.
Definition: mptrac.c:9072
void read_met_bin_3d(FILE *in, const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname, const float bound_min, const float bound_max)
Reads 3D meteorological data from a binary file, potentially using different compression methods.
Definition: mptrac.c:9101
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3927
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3915
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3987
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3957
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3951
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3933
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3909
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3984
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3897
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3996
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3891
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3903
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3936
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3948
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3954
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3942
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3924
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3918
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3900
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3912
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3990
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3930
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3975
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3939
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3906
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3945
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3993
Here is the call graph for this function:

◆ read_met_bin_2d()

void read_met_bin_2d ( FILE *  in,
const met_t met,
float  var[EX][EY],
const char *  varname 
)

Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array.

This function reads a 2-dimensional meteorological variable from a binary file, which is assumed to be uncompressed, and stores it in the provided 2-dimensional array var. The variable name is used for logging purposes to identify the data being read.

Parameters
inA pointer to the FILE structure representing the binary file to read from.
metA pointer to a structure containing meteorological data.
varA 2-dimensional array to store the read variable.
varnameA string containing the name of the variable being read.

The function performs the following steps:

  • Allocates memory for a temporary buffer to hold the uncompressed data.
  • Logs information about the variable being read from the file.
  • Reads the uncompressed data from the file into the temporary buffer.
  • Copies the data from the temporary buffer to the provided 2-dimensional array.
  • Frees the memory allocated for the temporary buffer.
Note
The function assumes that the binary file contains uncompressed data and reads the data directly into the provided array without any additional processing.
Author
Lars Hoffmann

Definition at line 9072 of file mptrac.c.

9076 {
9077
9078 float *help;
9079
9080 /* Allocate... */
9081 ALLOC(help, float,
9082 EX * EY);
9083
9084 /* Read uncompressed... */
9085 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
9086 FREAD(help, float,
9087 (size_t) (met->nx * met->ny),
9088 in);
9089
9090 /* Copy data... */
9091 for (int ix = 0; ix < met->nx; ix++)
9092 for (int iy = 0; iy < met->ny; iy++)
9093 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
9094
9095 /* Free... */
9096 free(help);
9097}

◆ read_met_bin_3d()

void read_met_bin_3d ( FILE *  in,
const ctl_t ctl,
const met_t met,
float  var[EX][EY][EP],
const char *  varname,
const float  bound_min,
const float  bound_max 
)

Reads 3D meteorological data from a binary file, potentially using different compression methods.

This function reads 3-dimensional meteorological data from a binary file into a specified variable array. The data can be read in uncompressed form or using one of several supported compression methods. The data is then clamped to specified minimum and maximum bounds.

Parameters
[in]inPointer to the input file from which to read the data.
[in]ctlPointer to the control structure that contains metadata about the type of data and how it is stored.
[in]metPointer to the meteorological structure that contains the dimensions of the data.
[out]var3D array to store the read data, with dimensions [EX][EY][EP].
[in]varnameName of the variable being read, used for logging and debugging.
[in]bound_minMinimum bound to which data values should be clamped.
[in]bound_maxMaximum bound to which data values should be clamped.

The function supports the following types of data:

  • Uncompressed data
  • Packed data
  • ZFP compressed data (if compiled with ZFP support)
  • ZSTD compressed data (if compiled with ZSTD support)
  • cmultiscale compressed data (if compiled with CMS support)

Depending on the compression type specified in the control structure, the appropriate reading and decompression function is used. The data is read into a temporary buffer, then copied into the output array, applying the specified bounds to each value.

Note
The function assumes that the dimensions EX, EY, and EP are correctly defined and match the dimensions specified in the met structure.
If the appropriate compression support is not compiled, an error message is generated.
Author
Lars Hoffmann

Definition at line 9101 of file mptrac.c.

9108 {
9109
9110 float *help;
9111
9112 /* Allocate... */
9113 ALLOC(help, float,
9114 EX * EY * EP);
9115
9116 /* Read uncompressed data... */
9117 if (ctl->met_type == 1) {
9118 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
9119 FREAD(help, float,
9120 (size_t) (met->nx * met->ny * met->np),
9121 in);
9122 }
9123
9124 /* Read packed data... */
9125 else if (ctl->met_type == 2)
9126 compress_pck(ctl, met, varname, help, 1, NULL, in);
9127
9128 /* Read ZFP data... */
9129 else if (ctl->met_type == 3) {
9130#ifdef ZFP
9131 int precision;
9132 FREAD(&precision, int,
9133 1,
9134 in);
9135
9136 double tolerance;
9137 FREAD(&tolerance, double,
9138 1,
9139 in);
9140
9141 compress_zfp(ctl, met, varname, help, 1, NULL, in);
9142#else
9143 ERRMSG("MPTRAC was compiled without ZFP compression!");
9144#endif
9145 }
9146
9147 /* Read zstd data... */
9148 else if (ctl->met_type == 4) {
9149#ifdef ZSTD
9150 compress_zstd(ctl, met, varname, help, 1, NULL, in);
9151#else
9152 ERRMSG("MPTRAC was compiled without ZSTD compression!");
9153#endif
9154 }
9155
9156 /* Read LZ4 data... */
9157 else if (ctl->met_type == 8) {
9158#ifdef LZ4
9159 compress_lz4(ctl, met, varname, help, 1, NULL, in);
9160#else
9161 ERRMSG("MPTRAC was compiled without LZ4 compression!");
9162#endif
9163 }
9164
9165 /* Read cmultiscale data... */
9166 else if (ctl->met_type == 5) {
9167#ifdef CMS
9168 compress_cms(ctl, met, varname, help, 1, NULL, in);
9169#else
9170 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
9171#endif
9172 }
9173
9174 /* Read SZ3 data... */
9175 else if (ctl->met_type == 7) {
9176#ifdef SZ3
9177 int precision;
9178 FREAD(&precision, int,
9179 1,
9180 in);
9181
9182 double tolerance;
9183 FREAD(&tolerance, double,
9184 1,
9185 in);
9186
9187 compress_sz3(ctl, met, varname, help, 1, NULL, in);
9188#else
9189 ERRMSG("MPTRAC was compiled without sz3 compression!");
9190#endif
9191 }
9192
9193 /* Copy data... */
9194#pragma omp parallel for default(shared) collapse(2)
9195 for (int ix = 0; ix < met->nx; ix++)
9196 for (int iy = 0; iy < met->ny; iy++)
9197 for (int ip = 0; ip < met->np; ip++) {
9198 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9199 if (var[ix][iy][ip] < bound_min)
9200 var[ix][iy][ip] = bound_min;
9201 else if (var[ix][iy][ip] > bound_max)
9202 var[ix][iy][ip] = bound_max;
9203 }
9204
9205 /* Free... */
9206 free(help);
9207}
void compress_pck(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3‑D float array using the PCK format.
Definition: mptrac.c:986
void compress_zfp(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
void compress_sz3(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3-D float array using the SZ3 library.
void compress_zstd(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a float array using ZSTD.
void compress_cms(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3-D meteorological field using cmultiscale.
void compress_lz4(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a float array using LZ4.
Here is the call graph for this function:

◆ read_met_cape()

void read_met_cape ( const ctl_t ctl,
const clim_t clim,
met_t met 
)

Calculates Convective Available Potential Energy (CAPE) for each grid point.

This function calculates the Convective Available Potential Energy (CAPE) at each grid point based on the provided meteorological data. CAPE is a measure of the energy available for deep convection, which is essential for severe weather development.

Parameters
ctlPointer to the control structure that contains metadata about the type of data and how it is stored.
climA pointer to a structure containing climatological data.
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the calculation time.
  • Initializes variables and constants required for the computation, such as vertical spacing and pressure levels.
  • Iterates over each grid point in parallel using OpenMP.
  • Calculates CAPE by integrating the difference in virtual temperatures between the environment and the parcel, up to the level of free convection (LFC).
  • Determines the lifted condensation level (LCL), level of free convection (LFC), equilibrium level (EL), and Convective Inhibition (CIN) for each grid point.
  • Checks the results and updates the corresponding fields in the meteorological data structure.
Note
The function utilizes OpenMP for parallelization to enhance performance by distributing the computation across multiple threads.
Author
Lars Hoffmann

Definition at line 9211 of file mptrac.c.

9214 {
9215
9216 /* Check parameters... */
9217 if (ctl->met_cape != 1)
9218 return;
9219
9220 if (ctl->met_coord_type != 0)
9221 ERRMSG("Only lat/lon grid supported");
9222
9223 /* Set timer... */
9224 SELECT_TIMER("READ_MET_CAPE", "METPROC");
9225 LOG(2, "Calculate CAPE...");
9226
9227 /* Vertical spacing (about 100 m)... */
9228 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
9229
9230 /* Loop over columns... */
9231#pragma omp parallel for default(shared) collapse(2)
9232 for (int ix = 0; ix < met->nx; ix++)
9233 for (int iy = 0; iy < met->ny; iy++) {
9234
9235 /* Get potential temperature and water vapor at lowest 50 hPa... */
9236 int n = 0;
9237 double h2o = 0, t, theta = 0;
9238 double pbot = MIN(met->ps[ix][iy], met->p[0]);
9239 double ptop = pbot - 50.;
9240 for (int ip = 0; ip < met->np; ip++) {
9241 if (met->p[ip] <= pbot) {
9242 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
9243 h2o += met->h2o[ix][iy][ip];
9244 n++;
9245 }
9246 if (met->p[ip] < ptop && n > 0)
9247 break;
9248 }
9249 theta /= n;
9250 h2o /= n;
9251
9252 /* Cannot compute anything if water vapor is missing... */
9253 met->plcl[ix][iy] = NAN;
9254 met->plfc[ix][iy] = NAN;
9255 met->pel[ix][iy] = NAN;
9256 met->cape[ix][iy] = NAN;
9257 met->cin[ix][iy] = NAN;
9258 if (h2o <= 0)
9259 continue;
9260
9261 /* Find lifted condensation level (LCL)... */
9262 ptop = P(20.);
9263 pbot = met->ps[ix][iy];
9264 do {
9265 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
9266 t = theta / pow(1000. / met->plcl[ix][iy], KAPPA);
9267 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
9268 ptop = met->plcl[ix][iy];
9269 else
9270 pbot = met->plcl[ix][iy];
9271 } while (pbot - ptop > 0.1);
9272
9273 /* Calculate CIN up to LCL... */
9275 double dcape, dz, h2o_env, t_env;
9276 double p = met->ps[ix][iy];
9277 met->cape[ix][iy] = met->cin[ix][iy] = 0;
9278 do {
9279 dz = dz0 * TVIRT(t, h2o);
9280 p /= pfac;
9281 t = theta / pow(1000. / p, KAPPA);
9282 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
9283 &t_env, ci, cw, 1);
9284 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
9285 &h2o_env, ci, cw, 0);
9286 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
9287 TVIRT(t_env, h2o_env) * dz;
9288 if (dcape < 0)
9289 met->cin[ix][iy] += fabsf((float) dcape);
9290 } while (p > met->plcl[ix][iy]);
9291
9292 /* Calculate level of free convection (LFC), equilibrium level (EL),
9293 and convective available potential energy (CAPE)... */
9294 dcape = 0;
9295 p = met->plcl[ix][iy];
9296 t = theta / pow(1000. / p, KAPPA);
9297 ptop = 0.75 * clim_tropo(clim, met->time,
9298 ctl->met_coord_type ==
9299 0 ? met->lat[iy] : ctl->met_utm_ref_lat);
9300 do {
9301 dz = dz0 * TVIRT(t, h2o);
9302 p /= pfac;
9303 t -= lapse_rate(t, h2o) * dz;
9304 double psat = PSAT(t);
9305 h2o = psat / (p - (1. - EPS) * psat);
9306 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
9307 &t_env, ci, cw, 1);
9308 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
9309 &h2o_env, ci, cw, 0);
9310 double dcape_old = dcape;
9311 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
9312 TVIRT(t_env, h2o_env) * dz;
9313 if (dcape > 0) {
9314 met->cape[ix][iy] += (float) dcape;
9315 if (!isfinite(met->plfc[ix][iy]))
9316 met->plfc[ix][iy] = (float) p;
9317 } else if (dcape_old > 0)
9318 met->pel[ix][iy] = (float) p;
9319 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
9320 met->cin[ix][iy] += fabsf((float) dcape);
9321 } while (p > ptop);
9322
9323 /* Check results... */
9324 if (!isfinite(met->plfc[ix][iy]))
9325 met->cin[ix][iy] = NAN;
9326 }
9327}
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:213
Here is the call graph for this function:

◆ read_met_cloud()

void read_met_cloud ( met_t met)

Calculates cloud-related variables for each grid point.

This function calculates cloud-related variables, such as cloud cover, cloud top pressure, cloud bottom pressure, and total cloud water content, based on the provided meteorological data.

Parameters
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the calculation time.
  • Initializes variables and constants required for the computation.
  • Iterates over each grid point in parallel using OpenMP.
  • Determines cloud-related variables based on thresholds for liquid water content (LWC), rain water content (RWC), ice water content (IWC) and snow water content (SWC).
  • Calculates cloud cover, cloud top pressure, cloud bottom pressure, and total cloud water content for each grid point.
  • Updates the corresponding fields in the meteorological data structure.
Note
The function utilizes OpenMP for parallelization to enhance performance by distributing the computation across multiple threads.
Author
Lars Hoffmann

Definition at line 9331 of file mptrac.c.

9332 {
9333
9334 /* Set timer... */
9335 SELECT_TIMER("READ_MET_CLOUD", "METPROC");
9336 LOG(2, "Calculate cloud data...");
9337
9338 /* Thresholds for cloud detection... */
9339 const double ccmin = 0.01, cwmin = 1e-6;
9340
9341 /* Loop over columns... */
9342#pragma omp parallel for default(shared) collapse(2)
9343 for (int ix = 0; ix < met->nx; ix++)
9344 for (int iy = 0; iy < met->ny; iy++) {
9345
9346 /* Init... */
9347 met->pct[ix][iy] = NAN;
9348 met->pcb[ix][iy] = NAN;
9349 met->cl[ix][iy] = 0;
9350
9351 /* Loop over pressure levels... */
9352 for (int ip = 0; ip < met->np - 1; ip++) {
9353
9354 /* Check pressure... */
9355 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
9356 continue;
9357
9358 /* Check ice water and liquid water content... */
9359 if (met->cc[ix][iy][ip] > ccmin
9360 && (met->lwc[ix][iy][ip] > cwmin
9361 || met->rwc[ix][iy][ip] > cwmin
9362 || met->iwc[ix][iy][ip] > cwmin
9363 || met->swc[ix][iy][ip] > cwmin)) {
9364
9365 /* Get cloud top pressure ... */
9366 met->pct[ix][iy]
9367 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
9368
9369 /* Get cloud bottom pressure ... */
9370 if (!isfinite(met->pcb[ix][iy]))
9371 met->pcb[ix][iy]
9372 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
9373 }
9374
9375 /* Get cloud water... */
9376 met->cl[ix][iy] += (float)
9377 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
9378 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
9379 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
9380 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
9381 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
9382 }
9383 }
9384}

◆ read_met_detrend()

void read_met_detrend ( const ctl_t ctl,
met_t met 
)

Detrends meteorological data.

This function detrends meteorological data by removing spatially varying backgrounds from each grid point. Detrending helps in removing systematic biases and trends from the data, enabling better analysis and modeling.

Parameters
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Checks if detrending is enabled based on the control parameters.
  • Sets up a timer to monitor the detrending time.
  • Allocates memory for a temporary meteorological data structure.
  • Calculates the standard deviation and box size for detrending.
  • Calculates the detrended data by subtracting spatially varying backgrounds.
  • Updates the original meteorological data with the detrended values.
  • Frees the allocated memory.
Note
Detrending is performed by subtracting spatially varying backgrounds calculated from neighboring grid points.
OpenMP is utilized for parallelization to enhance performance by distributing the computation across multiple threads.
Author
Lars Hoffmann

Definition at line 9388 of file mptrac.c.

9390 {
9391
9392 met_t *help;
9393
9394 /* Check parameters... */
9395 if (ctl->met_detrend <= 0)
9396 return;
9397
9398 if (ctl->met_coord_type != 0)
9399 ERRMSG("Only lat/lon grid supported");
9400
9401 /* Set timer... */
9402 SELECT_TIMER("READ_MET_DETREND", "METPROC");
9403 LOG(2, "Detrend meteo data...");
9404
9405 /* Allocate... */
9406 ALLOC(help, met_t, 1);
9407
9408 /* Calculate standard deviation... */
9409 const double sigma = ctl->met_detrend / 2.355;
9410 const double tssq = 2. * SQR(sigma);
9411
9412 /* Calculate box size in latitude... */
9413 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
9414 sy = MIN(MAX(1, sy), met->ny / 2);
9415
9416 /* Calculate background... */
9417#pragma omp parallel for default(shared) collapse(2)
9418 for (int ix = 0; ix < met->nx; ix++) {
9419 for (int iy = 0; iy < met->ny; iy++) {
9420
9421 /* Calculate Cartesian coordinates... */
9422 double x0[3];
9423 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
9424
9425 /* Calculate box size in longitude... */
9426 int sx =
9427 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
9428 fabs(met->lon[1] - met->lon[0]));
9429 sx = MIN(MAX(1, sx), met->nx / 2);
9430
9431 /* Init... */
9432 float wsum = 0;
9433 for (int ip = 0; ip < met->np; ip++) {
9434 help->t[ix][iy][ip] = 0;
9435 help->u[ix][iy][ip] = 0;
9436 help->v[ix][iy][ip] = 0;
9437 help->w[ix][iy][ip] = 0;
9438 }
9439
9440 /* Loop over neighboring grid points... */
9441 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
9442 int ix3 = ix2;
9443 if (ix3 < 0)
9444 ix3 += met->nx;
9445 else if (ix3 >= met->nx)
9446 ix3 -= met->nx;
9447 for (int iy2 = MAX(iy - sy, 0);
9448 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
9449
9450 /* Calculate Cartesian coordinates... */
9451 double x1[3];
9452 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
9453
9454 /* Calculate weighting factor... */
9455 const float w = (float) exp(-DIST2(x0, x1) / tssq);
9456
9457 /* Add data... */
9458 wsum += w;
9459 for (int ip = 0; ip < met->np; ip++) {
9460 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
9461 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
9462 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
9463 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
9464 }
9465 }
9466 }
9467
9468 /* Normalize... */
9469 for (int ip = 0; ip < met->np; ip++) {
9470 help->t[ix][iy][ip] /= wsum;
9471 help->u[ix][iy][ip] /= wsum;
9472 help->v[ix][iy][ip] /= wsum;
9473 help->w[ix][iy][ip] /= wsum;
9474 }
9475 }
9476 }
9477
9478 /* Subtract background... */
9479#pragma omp parallel for default(shared) collapse(3)
9480 for (int ix = 0; ix < met->nx; ix++)
9481 for (int iy = 0; iy < met->ny; iy++)
9482 for (int ip = 0; ip < met->np; ip++) {
9483 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
9484 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
9485 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
9486 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
9487 }
9488
9489 /* Free... */
9490 free(help);
9491}
void geo2cart(const double z, const double lon, const double lat, double *x)
Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates.
Definition: mptrac.c:2601
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:903
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:1019
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:921
Here is the call graph for this function:

◆ read_met_extrapolate()

void read_met_extrapolate ( met_t met)

Extrapolates meteorological data.

This function extrapolates meteorological data by filling missing or invalid data points with values from the nearest valid point above. Extrapolation is performed column-wise, ensuring that missing data points are replaced with valid values.

Parameters
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the extrapolation time.
  • Loops over each grid column in parallel.
  • Finds the lowest valid data point within each column.
  • Extrapolates missing or invalid data points by copying values from the nearest valid point above.
  • Updates the meteorological data structure with the extrapolated values.
Note
Extrapolation is performed by copying values from the nearest valid point above to fill missing or invalid data points. OpenMP is utilized for parallelization to enhance performance by distributing the computation across multiple threads.
Author
Lars Hoffmann

Definition at line 9495 of file mptrac.c.

9496 {
9497
9498 /* Set timer... */
9499 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC");
9500 LOG(2, "Extrapolate meteo data...");
9501
9502 /* Loop over columns... */
9503#pragma omp parallel for default(shared) collapse(2)
9504 for (int ix = 0; ix < met->nx; ix++)
9505 for (int iy = 0; iy < met->ny; iy++) {
9506
9507 /* Find lowest valid data point... */
9508 int ip0;
9509 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
9510 if (!isfinite(met->t[ix][iy][ip0])
9511 || !isfinite(met->u[ix][iy][ip0])
9512 || !isfinite(met->v[ix][iy][ip0])
9513 || !isfinite(met->w[ix][iy][ip0]))
9514 break;
9515
9516 /* Extrapolate... */
9517 for (int ip = ip0; ip >= 0; ip--) {
9518 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
9519 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
9520 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
9521 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
9522 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
9523 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
9524 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
9525 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
9526 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
9527 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
9528 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
9529 }
9530 }
9531}

◆ read_met_geopot()

void read_met_geopot ( const ctl_t ctl,
met_t met 
)

Calculates geopotential heights from meteorological data.

This function calculates geopotential heights from provided meteorological data using the hydrostatic equation. Geopotential heights are computed column-wise for each grid point based on the temperature, pressure, and surface height information. Optionally, the calculated geopotential heights can be smoothed horizontally using a weighted averaging scheme.

Parameters
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the geopotential height calculation time.
  • Calculates the logarithm of pressure levels for efficient computation.
  • Applies the hydrostatic equation to determine geopotential heights based on temperature, pressure, and height information.
  • Optionally, performs horizontal smoothing on the calculated geopotential heights.
  • Updates the meteorological data structure with the computed geopotential heights.
Note
The hydrostatic equation is utilized to calculate geopotential heights, ensuring consistency with atmospheric conditions. Optionally, horizontal smoothing can be applied to the calculated geopotential heights to reduce spatial variability. OpenMP is utilized for parallelization to enhance performance by distributing the computation across multiple threads.
Author
Lars Hoffmann

Definition at line 9535 of file mptrac.c.

9537 {
9538
9539 float *help;
9540
9541 double logp[EP];
9542
9543 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
9544
9545 /* Set timer... */
9546 SELECT_TIMER("READ_MET_GEOPOT", "METPROC");
9547 LOG(2, "Calculate geopotential heights...");
9548
9549 /* Allocate... */
9550 ALLOC(help, float,
9551 EX * EY * EP);
9552
9553 /* Calculate log pressure... */
9554#pragma omp parallel for default(shared)
9555 for (int ip = 0; ip < met->np; ip++)
9556 logp[ip] = log(met->p[ip]);
9557
9558 /* Apply hydrostatic equation to calculate geopotential heights... */
9559#pragma omp parallel for default(shared) collapse(2)
9560 for (int ix = 0; ix < met->nx; ix++)
9561 for (int iy = 0; iy < met->ny; iy++) {
9562
9563 /* Get surface height and pressure... */
9564 const double zs = met->zs[ix][iy];
9565 const double lnps = log(met->ps[ix][iy]);
9566
9567 /* Get temperature and water vapor at the surface... */
9568 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
9569 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
9570 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
9571 const double h2os =
9572 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
9573 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
9574
9575 /* Upper part of profile... */
9576 met->z[ix][iy][ip0 + 1]
9577 = (float) (zs +
9578 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
9579 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
9580 for (int ip = ip0 + 2; ip < met->np; ip++)
9581 met->z[ix][iy][ip]
9582 = (float) (met->z[ix][iy][ip - 1] +
9583 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
9584 met->h2o[ix][iy][ip - 1], logp[ip],
9585 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
9586
9587 /* Lower part of profile... */
9588 met->z[ix][iy][ip0]
9589 = (float) (zs +
9590 ZDIFF(lnps, ts, h2os, logp[ip0],
9591 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
9592 for (int ip = ip0 - 1; ip >= 0; ip--)
9593 met->z[ix][iy][ip]
9594 = (float) (met->z[ix][iy][ip + 1] +
9595 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
9596 met->h2o[ix][iy][ip + 1], logp[ip],
9597 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
9598 }
9599
9600 /* Check control parameters... */
9601 if (dx == 0 || dy == 0)
9602 return;
9603
9604 /* Default smoothing parameters... */
9605 if (dx < 0 || dy < 0) {
9606 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
9607 dx = 3;
9608 dy = 2;
9609 } else {
9610 dx = 6;
9611 dy = 4;
9612 }
9613 }
9614
9615 /* Calculate weights for smoothing... */
9616 float ws[dx + 1][dy + 1];
9617#pragma omp parallel for default(shared) collapse(2)
9618 for (int ix = 0; ix <= dx; ix++)
9619 for (int iy = 0; iy < dy; iy++)
9620 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
9621 * (1.0f - (float) iy / (float) dy);
9622
9623 /* Copy data... */
9624#pragma omp parallel for default(shared) collapse(3)
9625 for (int ix = 0; ix < met->nx; ix++)
9626 for (int iy = 0; iy < met->ny; iy++)
9627 for (int ip = 0; ip < met->np; ip++)
9628 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
9629
9630 /* Horizontal smoothing... */
9631#pragma omp parallel for default(shared) collapse(3)
9632 for (int ip = 0; ip < met->np; ip++)
9633 for (int ix = 0; ix < met->nx; ix++)
9634 for (int iy = 0; iy < met->ny; iy++) {
9635 float res = 0, wsum = 0;
9636 int iy0 = MAX(iy - dy + 1, 0);
9637 int iy1 = MIN(iy + dy - 1, met->ny - 1);
9638 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
9639 int ix3 = ix2;
9640 if (ix3 < 0)
9641 ix3 += met->nx;
9642 else if (ix3 >= met->nx)
9643 ix3 -= met->nx;
9644 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
9645 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
9646 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
9647 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
9648 wsum += w;
9649 }
9650 }
9651 if (wsum > 0)
9652 met->z[ix][iy][ip] = res / wsum;
9653 else
9654 met->z[ix][iy][ip] = NAN;
9655 }
9656
9657 /* Free... */
9658 free(help);
9659}
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:2273
Here is the call graph for this function:

◆ read_met_nc_grid()

void read_met_nc_grid ( const char *  filename,
const int  ncid,
const ctl_t ctl,
met_t met,
dd_t dd 
)

Reads meteorological grid data from NetCDF files with domain decomposition.

The read_met_nc_grid function reads meteorological data from NetCDF files and processes it with domain decomposition for parallel processing. It extracts time information, grid dimensions, and coordinates, and sets up hyperslabs for subdomains and halos. It also reads pressure levels and handles model level and surface data.

Parameters
filenameA string representing the filename of the NetCDF file to read.
ncidA NetCDF file ID.
ctlA pointer to a ctl_t structure containing control parameters.
metA pointer to a met_t structure where meteorological data will be stored.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.

The function performs the following steps:

  • Sets filenames for meteorological data files.
  • Extracts time information from the filename or NetCDF file.
  • Validates the time information and logs it.
  • Retrieves global and local grid dimensions and checks for regular grid spacing.
  • Sets up hyperslabs for subdomains and halos, considering edge cases.
  • Adjusts grid dimensions and coordinates for subdomains and halos.
  • Reads pressure levels and computes the 3D pressure field.
  • Handles model level and surface data using GRIB handles.
  • Reads grid data and surface data from the respective files.
  • Computes the 3D pressure field and reads model level data.
Note
This function assumes that the input filename and structures are properly initialized. It uses MPI for parallel processing and handles domain decomposition. The function is designed to work with NetCDF and GRIB file formats. It logs various stages of processing for debugging and validation purposes.
Author
Lars Hoffmann
Jan Clemens

Definition at line 9663 of file mptrac.c.

9668 {
9669
9670 char levname[LEN], tstr[10];
9671
9672 double rtime = 0, r, r2;
9673
9674 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
9675 year, mon, day, hour, min, sec;
9676
9677 size_t dimlen;
9678
9679 /* Set timer... */
9680 SELECT_TIMER("READ_MET_NC_GRID", "INPUT");
9681 LOG(2, "Read meteo grid information...");
9682
9683 /* MPTRAC meteo files... */
9684 if (!ctl->met_clams) {
9685
9686 /* Get time from filename... */
9687 met->time = time_from_filename(filename, 16, 0);
9688
9689 /* Check time information from data file... */
9690 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
9691 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
9692 NC(nc_get_var_double(ncid, varid, &rtime));
9693 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
9694 WARN("Time information in meteo file does not match filename!");
9695 } else
9696 WARN("Time information in meteo file is missing!");
9697 }
9698
9699 /* CLaMS meteo files... */
9700 else {
9701
9702 /* Read time from file... */
9703 NC_GET_DOUBLE("time", &rtime, 0);
9704
9705 /* Get time from filename (considering the century)... */
9706 if (rtime < 0)
9707 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
9708 else
9709 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
9710 year = atoi(tstr);
9711 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
9712 mon = atoi(tstr);
9713 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
9714 day = atoi(tstr);
9715 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
9716 hour = atoi(tstr);
9717 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
9718 }
9719
9720 /* Check time... */
9721 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
9722 || day < 1 || day > 31 || hour < 0 || hour > 23)
9723 ERRMSG("Cannot read time from filename!");
9724 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
9725 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
9726 met->time, year2, mon2, day2, hour2, min2);
9727
9728 /* Get vertical dimension... */
9729 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
9730 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
9731 ERRMSG
9732 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
9733
9734 NC(nc_inq_varndims(ncid, varid, &ndims));
9735 NC(nc_inq_vardimid(ncid, varid, dimids));
9736
9737 if (ndims == 4) {
9738 NC(nc_inq_dim
9739 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
9740 } else if (ndims == 3) {
9741 NC(nc_inq_dim
9742 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
9743 } else
9744 ERRMSG("Cannot determine vertical dimension!")
9745 met->np = (int) dimlen;
9746
9747 LOG(2, "Number of levels: %d", met->np);
9748 if (met->np < 2 || met->np > EP)
9749 ERRMSG("Number of levels out of range!");
9750
9751 if (!ctl->dd) {
9752
9753 /* Get grid dimensions and coordinates... */
9754 if (met->coord_type == 0) {
9755 /* Longitude/latitude grid... */
9756 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
9757 LOG(2, "Number of longitudes: %d", met->nx);
9758
9759 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
9760 LOG(2, "Number of latitudes: %d", met->ny);
9761
9762 NC_GET_DOUBLE("lon", met->lon, 1);
9763 LOG(2, "Longitudes: %g, %g ... %g deg",
9764 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9765 NC_GET_DOUBLE("lat", met->lat, 1);
9766 LOG(2, "Latitudes: %g, %g ... %g deg",
9767 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9768
9769 } else {
9770 /* UTM grid... */
9771 NC_INQ_DIM("x", &met->nx, 2, EX, 1);
9772 LOG(2, "Number of x coordinates: %d", met->nx);
9773
9774 NC_INQ_DIM("y", &met->ny, 2, EY, 1);
9775 LOG(2, "Number of y coordinates: %d", met->ny);
9776
9777 NC_GET_DOUBLE("x", met->lon, 1);
9778 LOG(2, "X coordinates: %g, %g ... %g m",
9779 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9780 NC_GET_DOUBLE("y", met->lat, 1);
9781 LOG(2, "Y coordinates: %g, %g ... %g m",
9782 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9783 }
9784
9785 } else {
9786
9787 if (met->coord_type != 0)
9788 ERRMSG("Domain decomposition is only supported for lat/lon grids!");
9789
9790 /* Use equidistant lat-lon domain decomposition... */
9791 dd_read_met_nc_grid(dd, ctl, met, ncid);
9792
9793 }
9794
9795 /* Read pressure levels... */
9796 if (ctl->met_np <= 0) {
9797 NC_GET_DOUBLE(levname, met->p, 1);
9798 for (int ip = 0; ip < met->np; ip++)
9799 met->p[ip] /= 100.;
9800 LOG(2, "Altitude levels: %g, %g ... %g km",
9801 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
9802 LOG(2, "Pressure levels: %g, %g ... %g hPa",
9803 met->p[0], met->p[1], met->p[met->np - 1]);
9804 }
9805
9806 /* Read hybrid levels... */
9807 if (strcasecmp(levname, "hybrid") == 0)
9808 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
9809
9810 /* Read model level coefficients from file... */
9811 if (ctl->met_vert_coord == 2) {
9812 NC_GET_DOUBLE("hyam", met->hyam, 1);
9813 NC_GET_DOUBLE("hybm", met->hybm, 1);
9814 }
9815
9816 /* Copy model level coefficients from control parameters... */
9817 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
9818 if (ctl->met_nlev <= 0)
9819 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
9820 for (int ip = 0; ip < ctl->met_nlev; ip++) {
9821 met->hyam[ip] = ctl->met_lev_hyam[ip];
9822 met->hybm[ip] = ctl->met_lev_hybm[ip];
9823 }
9824 }
9825
9826 /* Calculate eta levels... */
9827 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
9828 met->eta[k] = met->hyam[k] / (100.0 * P0) + met->hybm[k];
9829 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
9830 ERRMSG("Eta levels must be ascending!");
9831 }
9832
9833 /* Check horizontal grid spacing... */
9834 for (int ix = 2; ix < met->nx; ix++)
9835 if (fabs
9836 (fabs(met->lon[ix] - met->lon[ix - 1]) -
9837 fabs(met->lon[1] - met->lon[0])) > 0.001)
9838 ERRMSG("No regular grid spacing in longitudes!");
9839 for (int iy = 2; iy < met->ny; iy++)
9840 if (fabs
9841 (fabs(met->lat[iy] - met->lat[iy - 1]) -
9842 fabs(met->lat[1] - met->lat[0])) > 0.001) {
9843 WARN("No regular grid spacing in latitudes!");
9844 break;
9845 }
9846}
void dd_read_met_nc_grid(dd_t *dd, const ctl_t *ctl, met_t *met, const int ncid)
Read meteorological grid information and construct the domain-decomposed grid with halo regions.
Definition: mptrac.c:11429
void time2jsec(const int year, const int mon, const int day, const int hour, const int min, const int sec, const double remain, double *jsec)
Converts time components to seconds since January 1, 2000, 12:00:00 UTC.
Definition: mptrac.c:12635
double time_from_filename(const char *filename, const int offset, const int with_seconds)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:12734
#define P0
Standard pressure [hPa].
Definition: mptrac.h:304
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3876
double eta[EP]
Model level eta values.
Definition: mptrac.h:3885
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3879
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3882
Here is the call graph for this function:

◆ read_met_nc_surface()

void read_met_nc_surface ( const int  ncid,
const ctl_t ctl,
met_t met,
dd_t dd 
)

Reads and processes surface meteorological data from NetCDF files with domain decomposition.

The read_met_nc_surface function reads surface meteorological data from a NetCDF file and processes it for use in a domain decomposition context. It handles various surface parameters such as pressure, geopotential height, temperature, wind components, and other relevant meteorological data. The function is designed to work with different meteorological data formats and configurations.

Parameters
ncidAn integer representing the NetCDF file ID.
ctlA pointer to a ctl_t structure containing control parameters and settings.
metA pointer to a met_t structure where surface meteorological data will be stored.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.

The function performs the following steps:

  • Reads surface pressure data and converts it if necessary.
  • Handles different data formats for MPTRAC and CLaMS meteorological data.
  • Reads geopotential height at the surface and processes it based on the data format.
  • Optionally converts zm surface geopotential data from m^2 s^-2 to km when MET_GP2Z = 1.
  • Retrieves surface temperature, zonal and meridional wind, and other surface parameters.
  • Logs warnings if specific data fields cannot be read.
  • Uses helper functions to read 2D and 3D data fields from the NetCDF file.
  • Processes and stores the read data into the provided meteorological data structure.
Note
This function assumes that the NetCDF file ID and structures are properly initialized. It is designed to work with NetCDF files and uses MPI for parallel processing. The function logs warnings for missing or unreadable data fields and handles different data formats.
Author
Lars Hoffmann
Jan Clemens

Definition at line 9850 of file mptrac.c.

9854 {
9855
9856 /* Set timer... */
9857 SELECT_TIMER("READ_MET_SURFACE", "INPUT");
9858 LOG(2, "Read surface data...");
9859
9860 /* Read surface pressure... */
9861 if (read_met_nc_2d
9862 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
9863 1.0f, 1)) {
9864 for (int ix = 0; ix < met->nx; ix++)
9865 for (int iy = 0; iy < met->ny; iy++)
9866 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
9867 } else
9868 if (!read_met_nc_2d
9869 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
9870 0.01f, 1)) {
9871 WARN("Cannot not read surface pressure data (use lowest level)!");
9872 for (int ix = 0; ix < met->nx; ix++)
9873 for (int iy = 0; iy < met->ny; iy++)
9874 met->ps[ix][iy]
9875 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
9876 }
9877
9878 /* MPTRAC meteo data... */
9879 if (ctl->met_clams == 0) {
9880
9881 /* Read geopotential height at the surface... */
9882 if (!read_met_nc_2d
9883 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
9884 (float) (1. / (1000. * G0)), 1))
9885 if (!read_met_nc_2d
9886 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
9887 (ctl->met_gp2z ? (float) (1e-3 / G0) : (float) (1. / 1000.)), 1))
9888 WARN("Cannot read surface geopotential height!");
9889 }
9890
9891 /* CLaMS meteo data... */
9892 else {
9893
9894 /* Read geopotential height at the surface
9895 (use lowermost level of 3-D data field)... */
9896 float *help;
9897 ALLOC(help, float,
9898 EX * EY * EP);
9899 memcpy(help, met->pl, sizeof(met->pl));
9900 if (!read_met_nc_3d
9901 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
9902 (float) (1e-3 / G0)))
9903 ERRMSG("Cannot read geopotential height!");
9904 for (int ix = 0; ix < met->nx; ix++)
9905 for (int iy = 0; iy < met->ny; iy++)
9906 met->zs[ix][iy] = met->pl[ix][iy][0];
9907 memcpy(met->pl, help, sizeof(met->pl));
9908 free(help);
9909 }
9910
9911 /* Read temperature at the surface... */
9912 if (!read_met_nc_2d
9913 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
9914 1))
9915 WARN("Cannot read surface temperature!");
9916
9917 /* Read zonal wind at the surface... */
9918 if (!read_met_nc_2d
9919 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
9920 met->us, 1.0, 1))
9921 WARN("Cannot read surface zonal wind!");
9922
9923 /* Read meridional wind at the surface... */
9924 if (!read_met_nc_2d
9925 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
9926 met->vs, 1.0, 1))
9927 WARN("Cannot read surface meridional wind!");
9928
9929 /* Read eastward turbulent surface stress... */
9930 if (!read_met_nc_2d
9931 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
9932 1.0, 1))
9933 WARN("Cannot read eastward turbulent surface stress!");
9934
9935 /* Read northward turbulent surface stress... */
9936 if (!read_met_nc_2d
9937 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
9938 1.0, 1))
9939 WARN("Cannot read northward turbulent surface stress!");
9940
9941 /* Read surface sensible heat flux... */
9942 if (!read_met_nc_2d
9943 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
9944 1.0, 1))
9945 WARN("Cannot read surface sensible heat flux!");
9946
9947 /* Read land-sea mask... */
9948 if (!read_met_nc_2d
9949 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
9950 1.0, 1))
9951 WARN("Cannot read land-sea mask!");
9952
9953 /* Read sea surface temperature... */
9954 if (!read_met_nc_2d
9955 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
9956 1.0, 1))
9957 WARN("Cannot read sea surface temperature!");
9958
9959 /* Read PBL... */
9960 if (ctl->met_pbl == 0)
9961 if (!read_met_nc_2d
9962 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
9963 0.01f, 1))
9964 WARN("Cannot read planetary boundary layer pressure!");
9965 if (ctl->met_pbl == 1)
9966 if (!read_met_nc_2d
9967 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
9968 0.001f, 1))
9969 WARN("Cannot read planetary boundary layer height!");
9970
9971 /* Read CAPE... */
9972 if (ctl->met_cape == 0)
9973 if (!read_met_nc_2d
9974 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
9975 met->cape, 1.0, 1))
9976 WARN("Cannot read CAPE!");
9977
9978 /* Read CIN... */
9979 if (ctl->met_cape == 0)
9980 if (!read_met_nc_2d
9981 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
9982 1.0, 1))
9983 WARN("Cannot read convective inhibition!");
9984}
int read_met_nc_2d(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const char *varname5, const char *varname6, const ctl_t *ctl, const met_t *met, dd_t *dd, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:10188
int read_met_nc_3d(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const ctl_t *ctl, const met_t *met, dd_t *dd, float dest[EX][EY][EP], const float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:10510
Here is the call graph for this function:

◆ read_met_nc_levels()

void read_met_nc_levels ( const int  ncid,
const ctl_t ctl,
met_t met,
dd_t dd 
)

Reads and processes meteorological level data from NetCDF files with domain decomposition.

The read_met_nc_levels function reads meteorological level data from a NetCDF file and processes it for use in a domain decomposition context. It handles various meteorological parameters such as temperature, wind components, humidity, ozone, cloud data, and vertical velocity. The function also processes pressure levels and interpolates data between model and pressure levels as needed.

Parameters
ncidAn integer representing the NetCDF file ID.
ctlA pointer to a ctl_t structure containing control parameters and settings.
metA pointer to a met_t structure where meteorological level data will be stored.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.

The function performs the following steps:

  • Reads temperature, horizontal wind components, and vertical velocity data.
  • Processes water vapor data, handling both specific and relative humidity.
  • Reads ozone and various cloud-related data such as liquid water content, ice water content, and cloud cover.
  • Processes zeta and zeta_dot data.
  • Stores velocities on model levels and saves the number of model levels.
  • Computes pressure on model levels using different methods based on control parameters.
  • Checks the ordering of pressure levels to ensure they are monotonic.
  • Interpolates meteorological variables from model levels to pressure levels if specified.
  • Validates the ordering of pressure levels to ensure they are in descending order.
Note
This function assumes that the NetCDF file ID and structures are properly initialized. It is designed to work with NetCDF files and uses OpenMP for parallel processing. The function logs errors and warnings for missing or unreadable data fields and handles different data formats.
Author
Lars Hoffmann
Jan Clemens

Definition at line 9988 of file mptrac.c.

9992 {
9993
9994 /* Set timer... */
9995 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT");
9996 LOG(2, "Read level data...");
9997
9998 /* Read temperature... */
9999 if (!read_met_nc_3d
10000 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
10001 ERRMSG("Cannot read temperature!");
10002
10003 /* Read horizontal wind and vertical velocity... */
10004 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
10005 ERRMSG("Cannot read zonal wind!");
10006 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
10007 ERRMSG("Cannot read meridional wind!");
10008 if (!read_met_nc_3d
10009 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
10010 WARN("Cannot read vertical velocity!");
10011
10012 /* Read water vapor... */
10013 if (!ctl->met_relhum) {
10014 if (!read_met_nc_3d
10015 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
10016 (float) (MA / MH2O)))
10017 WARN("Cannot read specific humidity!");
10018 } else {
10019 if (!read_met_nc_3d
10020 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
10021 WARN("Cannot read relative humidity!");
10022#pragma omp parallel for default(shared) collapse(2)
10023 for (int ix = 0; ix < met->nx; ix++)
10024 for (int iy = 0; iy < met->ny; iy++)
10025 for (int ip = 0; ip < met->np; ip++) {
10026 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
10027 met->h2o[ix][iy][ip] =
10028 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
10029 }
10030 }
10031
10032 /* Read ozone... */
10033 if (!read_met_nc_3d
10034 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
10035 (float) (MA / MO3)))
10036 WARN("Cannot read ozone data!");
10037
10038 /* Read cloud data... */
10039 if (!read_met_nc_3d
10040 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
10041 WARN("Cannot read cloud liquid water content!");
10042 if (!read_met_nc_3d
10043 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
10044 WARN("Cannot read cloud rain water content!");
10045 if (!read_met_nc_3d
10046 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
10047 WARN("Cannot read cloud ice water content!");
10048 if (!read_met_nc_3d
10049 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
10050 WARN("Cannot read cloud snow water content!");
10051 if (!read_met_nc_3d
10052 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
10053 WARN("Cannot read cloud cover!");
10054
10055 /* Read zeta and zeta_dot... */
10056 if (ctl->advect_vert_coord == 1) {
10057 if (!read_met_nc_3d
10058 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
10059 WARN("Cannot read ZETA!");
10060 if (!read_met_nc_3d
10061 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
10062 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
10063 ERRMSG("Cannot read ZETA_DOT!");
10064 }
10065
10066 /* Set eta coordinate on native model levels... */
10067 if (ctl->advect_vert_coord == 3 || ctl->qnt_eta_d >= 0) {
10068#pragma omp parallel for default(shared)
10069 for (int ix = 0; ix < met->nx; ix++)
10070 for (int iy = 0; iy < met->ny; iy++)
10071 for (int ip = 0; ip < met->np; ip++)
10072 met->zetal[ix][iy][ip] =
10073 (float) (met->hyam[ip] / (100.0 * P0) + met->hybm[ip]);
10074 }
10075
10076 /* Read eta_dot... */
10077 if (ctl->advect_vert_coord == 3)
10078 if (!read_met_nc_3d
10079 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
10080 1.0))
10081 ERRMSG("Cannot read eta vertical velocity!");
10082
10083 /* Store velocities on model levels... */
10084 if (ctl->met_vert_coord != 0) {
10085#pragma omp parallel for default(shared)
10086 for (int ix = 0; ix < met->nx; ix++)
10087 for (int iy = 0; iy < met->ny; iy++)
10088 for (int ip = 0; ip < met->np; ip++) {
10089 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
10090 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
10091 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
10092 }
10093
10094 /* Save number of model levels... */
10095 met->npl = met->np;
10096 }
10097
10098 /* Get pressure on model levels... */
10099 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
10100
10101 /* Read 3-D pressure field... */
10102 if (ctl->met_vert_coord == 1) {
10103 if (!read_met_nc_3d
10104 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
10105 0.01f))
10106 if (!read_met_nc_3d
10107 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
10108 ERRMSG("Cannot read pressure on model levels!");
10109 }
10110
10111 /* Use a and b coefficients for full levels (at layer midpoints)... */
10112 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
10113
10114 /* Check number of levels... */
10115 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
10116 ERRMSG("Mismatch in number of model levels!");
10117
10118 /* Calculate pressure... */
10119 for (int ix = 0; ix < met->nx; ix++)
10120 for (int iy = 0; iy < met->ny; iy++)
10121 for (int ip = 0; ip < met->np; ip++)
10122 met->pl[ix][iy][ip] =
10123 (float) (met->hyam[ip] / 100. +
10124 met->hybm[ip] * met->ps[ix][iy]);
10125 }
10126
10127 /* Use a and b coefficients for half levels (at layer interfaces)... */
10128 else if (ctl->met_vert_coord == 4) {
10129
10130 /* Check number of levels... */
10131 if (met->np + 1 != ctl->met_nlev)
10132 ERRMSG("Mismatch in number of model levels!");
10133
10134 /* Calculate pressure... */
10135#pragma omp parallel for default(shared) collapse(2)
10136 for (int ix = 0; ix < met->nx; ix++)
10137 for (int iy = 0; iy < met->ny; iy++)
10138 for (int ip = 0; ip < met->np; ip++) {
10139 const double p0 =
10140 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
10141 const double p1 =
10142 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
10143 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
10144 }
10145 }
10146
10147 /* Check ordering of pressure levels... */
10148 for (int ix = 0; ix < met->nx; ix++)
10149 for (int iy = 0; iy < met->ny; iy++)
10150 for (int ip = 1; ip < met->np; ip++)
10151 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
10152 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
10153 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
10154 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
10155 ERRMSG("Pressure profiles are not monotonic!");
10156 }
10157
10158 /* Interpolate from model levels to pressure levels... */
10159 if (ctl->met_np > 0) {
10160
10161 /* Interpolate variables... */
10162 read_met_ml2pl(ctl, met, met->t, "T");
10163 read_met_ml2pl(ctl, met, met->u, "U");
10164 read_met_ml2pl(ctl, met, met->v, "V");
10165 read_met_ml2pl(ctl, met, met->w, "W");
10166 read_met_ml2pl(ctl, met, met->h2o, "H2O");
10167 read_met_ml2pl(ctl, met, met->o3, "O3");
10168 read_met_ml2pl(ctl, met, met->lwc, "LWC");
10169 read_met_ml2pl(ctl, met, met->rwc, "RWC");
10170 read_met_ml2pl(ctl, met, met->iwc, "IWC");
10171 read_met_ml2pl(ctl, met, met->swc, "SWC");
10172 read_met_ml2pl(ctl, met, met->cc, "CC");
10173
10174 /* Set new pressure levels... */
10175 met->np = ctl->met_np;
10176 for (int ip = 0; ip < met->np; ip++)
10177 met->p[ip] = ctl->met_p[ip];
10178 }
10179
10180 /* Check ordering of pressure levels... */
10181 for (int ip = 1; ip < met->np; ip++)
10182 if (met->p[ip - 1] < met->p[ip])
10183 ERRMSG("Pressure levels must be descending!");
10184}
void read_met_ml2pl(const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname)
Interpolates meteorological data to specified pressure levels.
Definition: mptrac.c:11259
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:294
#define MO3
Molar mass of ozone [g/mol].
Definition: mptrac.h:299
Here is the call graph for this function:

◆ read_met_nc_2d()

int read_met_nc_2d ( const int  ncid,
const char *  varname,
const char *  varname2,
const char *  varname3,
const char *  varname4,
const char *  varname5,
const char *  varname6,
const ctl_t ctl,
const met_t met,
dd_t dd,
float  dest[EX][EY],
const float  scl,
const int  init 
)

Reads a 2-dimensional meteorological variable from a NetCDF file.

This function reads a 2-dimensional meteorological variable from a NetCDF file and stores it in a specified destination array. It supports both packed and unpacked data formats and handles missing values and scaling factors accordingly. The function also checks the meteorological data layout to ensure correct data copying.

Parameters
ncidThe NetCDF file ID.
varnameThe name of the variable to read.
varname2An alternative name of the variable to read (in case varname is not found).
varname3An alternative name of the variable to read (in case varname2 is not found).
varname4An alternative name of the variable to read (in case varname3 is not found).
varname5An alternative name of the variable to read (in case varname4 is not found).
varname6An alternative name of the variable to read (in case varname5 is not found).
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.
destThe destination array to store the read data.
sclA scaling factor to apply to the read data.
initFlag indicating whether to initialize the destination array before reading.
Returns
Returns 1 on success, 0 on failure.

The function performs the following steps:

  • Checks if the specified variable exists in the NetCDF file.
  • Reads packed data if scaling factors are available, otherwise reads unpacked data.
  • Handles missing values and scaling factors appropriately.
  • Copies the data to the destination array, applying the scaling factor if provided.
Author
Lars Hoffmann

Definition at line 10188 of file mptrac.c.

10201 {
10202
10203 char varsel[LEN];
10204
10205 float offset, scalfac;
10206
10207 int varid;
10208
10209 /* Check if variable exists... */
10210 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
10211 sprintf(varsel, "%s", varname);
10212 else if (varname2 != NULL
10213 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
10214 sprintf(varsel, "%s", varname2);
10215 else if (varname3 != NULL
10216 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
10217 sprintf(varsel, "%s", varname3);
10218 else if (varname4 != NULL
10219 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
10220 sprintf(varsel, "%s", varname4);
10221 else if (varname5 != NULL
10222 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
10223 sprintf(varsel, "%s", varname5);
10224 else if (varname6 != NULL
10225 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
10226 sprintf(varsel, "%s", varname6);
10227 else
10228 return 0;
10229
10230 /* Read packed data... */
10231 if (ctl->met_nc_scale && !ctl->dd
10232 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
10233 && nc_get_att_float(ncid, varid, "scale_factor",
10234 &scalfac) == NC_NOERR) {
10235
10236 /* Allocate... */
10237 short *help;
10238 ALLOC(help, short,
10239 EX * EY * EP);
10240
10241 /* Read fill value and missing value... */
10242 short fillval, missval;
10243 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10244 fillval = 0;
10245 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
10246 missval = 0;
10247
10248 /* Write info... */
10249 LOG(2, "Read 2-D variable: %s"
10250 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
10251 varsel, fillval, missval, scalfac, offset);
10252
10253 /* Read data... */
10254 NC(nc_get_var_short(ncid, varid, help));
10255
10256 /* Check meteo data layout... */
10257 if (ctl->met_convention != 0)
10258 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
10259
10260 /* Copy and check data... */
10261 omp_set_dynamic(1);
10262#pragma omp parallel for default(shared)
10263 for (int ix = 0; ix < met->nx; ix++)
10264 for (int iy = 0; iy < met->ny; iy++) {
10265 if (init)
10266 dest[ix][iy] = 0;
10267 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
10268 if ((fillval == 0 || aux != fillval)
10269 && (missval == 0 || aux != missval)
10270 && fabsf(aux * scalfac + offset) < 1e14f)
10271 dest[ix][iy] += scl * (aux * scalfac + offset);
10272 else
10273 dest[ix][iy] = NAN;
10274 }
10275 omp_set_dynamic(0);
10276
10277 /* Free... */
10278 free(help);
10279 }
10280
10281 /* Unpacked data... */
10282 else if (!ctl->dd) {
10283
10284 /* Allocate... */
10285 float *help;
10286 ALLOC(help, float,
10287 EX * EY);
10288
10289 /* Read fill value and missing value... */
10290 float fillval, missval;
10291 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10292 fillval = 0;
10293 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10294 missval = 0;
10295
10296 /* Write info... */
10297 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
10298 varsel, fillval, missval);
10299
10300 /* Read data... */
10301 NC(nc_get_var_float(ncid, varid, help));
10302
10303 /* Check meteo data layout... */
10304 if (ctl->met_convention == 0) {
10305
10306 /* Copy and check data (ordering: lat, lon)... */
10307 omp_set_dynamic(1);
10308#pragma omp parallel for default(shared)
10309 for (int ix = 0; ix < met->nx; ix++)
10310 for (int iy = 0; iy < met->ny; iy++) {
10311 if (init)
10312 dest[ix][iy] = 0;
10313 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
10314 if ((fillval == 0 || aux != fillval)
10315 && (missval == 0 || aux != missval)
10316 && fabsf(aux) < 1e14f)
10317 dest[ix][iy] += scl * aux;
10318 else
10319 dest[ix][iy] = NAN;
10320 }
10321 omp_set_dynamic(0);
10322
10323 } else {
10324
10325 /* Copy and check data (ordering: lon, lat)... */
10326 omp_set_dynamic(1);
10327#pragma omp parallel for default(shared)
10328 for (int iy = 0; iy < met->ny; iy++)
10329 for (int ix = 0; ix < met->nx; ix++) {
10330 if (init)
10331 dest[ix][iy] = 0;
10332 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
10333 if ((fillval == 0 || aux != fillval)
10334 && (missval == 0 || aux != missval)
10335 && fabsf(aux) < 1e14f)
10336 dest[ix][iy] += scl * aux;
10337 else
10338 dest[ix][iy] = NAN;
10339 }
10340 omp_set_dynamic(0);
10341 }
10342
10343 /* Free... */
10344 free(help);
10345 }
10346
10347 /* Domain decomposed data... */
10348 else {
10349
10350 /* Read fill value and missing value... */
10351 float fillval, missval;
10352 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10353 fillval = 0;
10354 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10355 missval = 0;
10356
10357 /* Write info... */
10358 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
10359 varsel, fillval, missval);
10360
10361 /* Define hyperslab... */
10362 float *help;
10363 size_t help_subdomain_start[3];
10364 size_t help_subdomain_count[3];
10365
10366 help_subdomain_start[0] = 0;
10367 if (ctl->met_convention == 0) {
10368 help_subdomain_start[1] = dd->subdomain_start[2];
10369 help_subdomain_start[2] = dd->subdomain_start[3];
10370 } else {
10371 help_subdomain_start[1] = dd->subdomain_start[3];
10372 help_subdomain_start[2] = dd->subdomain_start[2];
10373 }
10374
10375 help_subdomain_count[0] = 1;
10376 if (ctl->met_convention == 0) {
10377 help_subdomain_count[1] = dd->subdomain_count[2]; //y
10378 help_subdomain_count[2] = dd->subdomain_count[3]; //x
10379 } else {
10380 help_subdomain_count[1] = dd->subdomain_count[3]; //x
10381 help_subdomain_count[2] = dd->subdomain_count[2]; //y
10382 }
10383
10384 ALLOC(help, float,
10385 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
10386
10387 /* Read data... */
10388#ifdef DD
10389 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
10390#endif
10391 NC(nc_get_vara_float
10392 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
10393
10394 /* Read halos at boundaries... */
10395 size_t help_halo_bnd_start[3];
10396 size_t help_halo_bnd_count[3];
10397
10398 help_halo_bnd_start[0] = 0;
10399 if (ctl->met_convention == 0) {
10400 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
10401 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
10402 } else {
10403 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
10404 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
10405 }
10406
10407 help_halo_bnd_count[0] = 1;
10408 if (ctl->met_convention == 0) {
10409 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
10410 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
10411 } else {
10412 help_halo_bnd_count[1] = dd->halo_bnd_count[3]; //x
10413 help_halo_bnd_count[2] = dd->halo_bnd_count[2]; //y
10414 }
10415
10416 float *help_halo;
10417 ALLOC(help_halo, float,
10418 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
10419
10420#ifdef DD
10421 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
10422#endif
10423 NC(nc_get_vara_float
10424 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
10425
10426 /* Check meteo data layout... */
10427 if (ctl->met_convention == 0) {
10428
10429 /* Copy and check data (ordering: lat, lon)... */
10430 omp_set_dynamic(1);
10431#pragma omp parallel for default(shared)
10432 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
10433 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
10434 if (init == 1)
10435 dest[ix + dd->halo_offset_start][iy] = 0;
10436 const float aux =
10437 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
10438 if ((fillval == 0 || aux != fillval)
10439 && (missval == 0 || aux != missval)
10440 && fabsf(aux) < 1e14f) {
10441 dest[ix + dd->halo_offset_start][iy] += scl * aux;
10442 } else
10443 dest[ix + dd->halo_offset_start][iy] = NAN;
10444 }
10445
10446#pragma omp parallel for default(shared)
10447 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
10448 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
10449 if (init == 1)
10450 dest[ix + dd->halo_offset_end][iy] = 0;
10451 const float aux =
10452 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
10453 if ((fillval == 0 || aux != fillval)
10454 && (missval == 0 || aux != missval)
10455 && fabsf(aux) < 1e14f)
10456 dest[ix + dd->halo_offset_end][iy] += scl * aux;
10457 else {
10458 dest[ix + dd->halo_offset_end][iy] = NAN;
10459 }
10460 }
10461 omp_set_dynamic(0);
10462
10463 } else {
10464
10465 /* Copy and check data (ordering: lon, lat)... */
10466 omp_set_dynamic(1);
10467#pragma omp parallel for default(shared)
10468 for (int ix = 0; ix < (int) help_subdomain_count[1]; ix++)
10469 for (int iy = 0; iy < (int) help_subdomain_count[2]; iy++) {
10470 if (init == 1)
10471 dest[ix + dd->halo_offset_start][iy] = 0;
10472 const float aux =
10473 help[ARRAY_2D(ix, iy, (int) help_subdomain_count[1])];
10474 if ((fillval == 0 || aux != fillval)
10475 && (missval == 0 || aux != missval)
10476 && fabsf(aux) < 1e14f)
10477 dest[ix + dd->halo_offset_start][iy] += scl * aux;
10478 else
10479 dest[ix + dd->halo_offset_start][iy] = NAN;
10480 }
10481
10482#pragma omp parallel for default(shared)
10483 for (int ix = 0; ix < (int) help_halo_bnd_count[1]; ix++)
10484 for (int iy = 0; iy < (int) help_halo_bnd_count[2]; iy++) {
10485 if (init == 1)
10486 dest[ix + dd->halo_offset_end][iy] = 0;
10487 const float aux =
10488 help_halo[ARRAY_2D(ix, iy, (int) help_halo_bnd_count[1])];
10489 if ((fillval == 0 || aux != fillval)
10490 && (missval == 0 || aux != missval)
10491 && fabsf(aux) < 1e14f)
10492 dest[ix + dd->halo_offset_end][iy] += scl * aux;
10493 else
10494 dest[ix + dd->halo_offset_end][iy] = NAN;
10495 }
10496 omp_set_dynamic(0);
10497 }
10498
10499 /* Free... */
10500 free(help);
10501 free(help_halo);
10502 }
10503
10504 /* Return... */
10505 return 1;
10506}
size_t halo_bnd_count[4]
Extent of the periodic boundary halo hyperslab.
Definition: mptrac.h:4055
int halo_offset_end
Offset of the periodic halo block at the end of the local x-array.
Definition: mptrac.h:4061
size_t halo_bnd_start[4]
Start indices of the periodic boundary halo hyperslab.
Definition: mptrac.h:4052
int halo_offset_start
Offset of the periodic halo block at the beginning of the local x-array.
Definition: mptrac.h:4058
size_t subdomain_count[4]
Extent of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:4049
size_t subdomain_start[4]
Start indices of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:4046

◆ read_met_nc_3d()

int read_met_nc_3d ( const int  ncid,
const char *  varname,
const char *  varname2,
const char *  varname3,
const char *  varname4,
const ctl_t ctl,
const met_t met,
dd_t dd,
float  dest[EX][EY][EP],
const float  scl 
)

Reads a 3-dimensional meteorological variable from a NetCDF file.

This function reads a 3-dimensional meteorological variable from a NetCDF file and stores it in a specified destination array. It supports both packed and unpacked data formats and handles missing values and scaling factors accordingly. The function also checks the meteorological data layout to ensure correct data copying.

Parameters
ncidThe NetCDF file ID.
varnameThe name of the variable to read.
varname2An alternative name of the variable to read (in case varname is not found).
varname3An alternative name of the variable to read (in case varname2 is not found).
varname4An alternative name of the variable to read (in case varname3 is not found).
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.
destThe destination array to store the read data.
sclA scaling factor to apply to the read data.
Returns
Returns 1 on success, 0 on failure.

The function performs the following steps:

  • Checks if the specified variable exists in the NetCDF file.
  • Reads packed data if scaling factors are available, otherwise reads unpacked data.
  • Handles missing values and scaling factors appropriately.
  • Copies the data to the destination array, applying the scaling factor if provided.
Author
Lars Hoffmann

Definition at line 10510 of file mptrac.c.

10520 {
10521
10522 char varsel[LEN];
10523
10524 float offset, scalfac;
10525
10526 int varid;
10527
10528 /* Check if variable exists... */
10529 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
10530 sprintf(varsel, "%s", varname);
10531 else if (varname2 != NULL
10532 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
10533 sprintf(varsel, "%s", varname2);
10534 else if (varname3 != NULL
10535 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
10536 sprintf(varsel, "%s", varname3);
10537 else if (varname4 != NULL
10538 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
10539 sprintf(varsel, "%s", varname4);
10540 else
10541 return 0;
10542
10543 /* Read packed data... */
10544 if (ctl->met_nc_scale && !ctl->dd
10545 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
10546 && nc_get_att_float(ncid, varid, "scale_factor",
10547 &scalfac) == NC_NOERR) {
10548
10549 /* Allocate... */
10550 short *help;
10551 ALLOC(help, short,
10552 EX * EY * EP);
10553
10554 /* Read fill value and missing value... */
10555 short fillval, missval;
10556 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10557 fillval = 0;
10558 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
10559 missval = 0;
10560
10561 /* Write info... */
10562 LOG(2, "Read 3-D variable: %s "
10563 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
10564 varsel, fillval, missval, scalfac, offset);
10565
10566 /* Read data... */
10567 NC(nc_get_var_short(ncid, varid, help));
10568
10569 /* Check meteo data layout... */
10570 if (ctl->met_convention != 0)
10571 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
10572
10573 /* Copy and check data... */
10574 omp_set_dynamic(1);
10575#pragma omp parallel for default(shared)
10576 for (int ix = 0; ix < met->nx; ix++)
10577 for (int iy = 0; iy < met->ny; iy++)
10578 for (int ip = 0; ip < met->np; ip++) {
10579 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
10580 if ((fillval == 0 || aux != fillval)
10581 && (missval == 0 || aux != missval)
10582 && fabsf(aux * scalfac + offset) < 1e14f)
10583 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
10584 else
10585 dest[ix][iy][ip] = NAN;
10586 }
10587 omp_set_dynamic(0);
10588
10589 /* Free... */
10590 free(help);
10591 }
10592
10593 /* Unpacked data... */
10594 else if (!ctl->dd) {
10595
10596 /* Allocate... */
10597 float *help;
10598 ALLOC(help, float,
10599 EX * EY * EP);
10600
10601 /* Read fill value and missing value... */
10602 float fillval, missval;
10603 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10604 fillval = 0;
10605 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10606 missval = 0;
10607
10608 /* Write info... */
10609 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
10610 varsel, fillval, missval);
10611
10612 /* Read data... */
10613 NC(nc_get_var_float(ncid, varid, help));
10614
10615 /* Check meteo data layout... */
10616 if (ctl->met_convention == 0) {
10617
10618 /* Copy and check data (ordering: lev, lat, lon)... */
10619 omp_set_dynamic(1);
10620#pragma omp parallel for default(shared)
10621 for (int ix = 0; ix < met->nx; ix++)
10622 for (int iy = 0; iy < met->ny; iy++)
10623 for (int ip = 0; ip < met->np; ip++) {
10624 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
10625 if ((fillval == 0 || aux != fillval)
10626 && (missval == 0 || aux != missval)
10627 && fabsf(aux) < 1e14f)
10628 dest[ix][iy][ip] = scl * aux;
10629 else
10630 dest[ix][iy][ip] = NAN;
10631 }
10632 omp_set_dynamic(0);
10633
10634 } else {
10635
10636 /* Copy and check data (ordering: lon, lat, lev)... */
10637 omp_set_dynamic(1);
10638#pragma omp parallel for default(shared)
10639 for (int ip = 0; ip < met->np; ip++)
10640 for (int iy = 0; iy < met->ny; iy++)
10641 for (int ix = 0; ix < met->nx; ix++) {
10642 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
10643 if ((fillval == 0 || aux != fillval)
10644 && (missval == 0 || aux != missval)
10645 && fabsf(aux) < 1e14f)
10646 dest[ix][iy][ip] = scl * aux;
10647 else
10648 dest[ix][iy][ip] = NAN;
10649 }
10650 omp_set_dynamic(0);
10651 }
10652
10653 /* Free... */
10654 free(help);
10655 }
10656
10657 /* Domain decomposed data... */
10658 else {
10659
10660 /* Read fill value and missing value... */
10661 float fillval, missval;
10662 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10663 fillval = 0;
10664 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10665 missval = 0;
10666
10667 /* Write info... */
10668 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
10669 varsel, fillval, missval);
10670
10671 /* Define hyperslab... */
10672 size_t help_subdomain_start[4];
10673 size_t help_subdomain_count[4];
10674 size_t help_halo_bnd_start[4];
10675 size_t help_halo_bnd_count[4];
10676
10677 if (ctl->met_convention == 0) {
10678 for (int i = 0; i < 4; i++) {
10679 help_subdomain_start[i] = dd->subdomain_start[i];
10680 help_subdomain_count[i] = dd->subdomain_count[i];
10681 help_halo_bnd_start[i] = dd->halo_bnd_start[i];
10682 help_halo_bnd_count[i] = dd->halo_bnd_count[i];
10683 }
10684 } else {
10685 help_subdomain_start[0] = dd->subdomain_start[0];
10686 help_subdomain_start[1] = dd->subdomain_start[3];
10687 help_subdomain_start[2] = dd->subdomain_start[2];
10688 help_subdomain_start[3] = dd->subdomain_start[1];
10689
10690 help_subdomain_count[0] = dd->subdomain_count[0];
10691 help_subdomain_count[1] = dd->subdomain_count[3];
10692 help_subdomain_count[2] = dd->subdomain_count[2];
10693 help_subdomain_count[3] = dd->subdomain_count[1];
10694
10695 help_halo_bnd_start[0] = dd->halo_bnd_start[0];
10696 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
10697 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
10698 help_halo_bnd_start[3] = dd->halo_bnd_start[1];
10699
10700 help_halo_bnd_count[0] = dd->halo_bnd_count[0];
10701 help_halo_bnd_count[1] = dd->halo_bnd_count[3];
10702 help_halo_bnd_count[2] = dd->halo_bnd_count[2];
10703 help_halo_bnd_count[3] = dd->halo_bnd_count[1];
10704 }
10705
10706 /* Allocate... */
10707 float *help;
10708 ALLOC(help, float,
10709 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
10710 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
10711
10712 /* Use default NetCDF parallel I/O behavior */
10713#ifdef DD
10714 NC(nc_var_par_access(ncid, varid, NC_INDEPENDENT));
10715#endif
10716 NC(nc_get_vara_float
10717 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
10718
10719 /* Read halos separately at boundaries... */
10720 float *help_halo;
10721 ALLOC(help_halo, float,
10722 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
10723 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
10724
10725#ifdef DD
10726 NC(nc_var_par_access(ncid, varid, NC_INDEPENDENT));
10727#endif
10728 if (dd->halo_bnd_count[1] > 0 && dd->halo_bnd_count[2] > 0
10729 && dd->halo_bnd_count[3] > 0) {
10730 NC(nc_get_vara_float
10731 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
10732 }
10733
10734 /* Check meteo data layout... */
10735 if (ctl->met_convention == 0) {
10736
10737 /* Copy and check data (ordering: lev, lat, lon)... */
10738 omp_set_dynamic(1);
10739#pragma omp parallel for default(shared)
10740 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10741 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10742 for (int ip = 0; ip < met->np; ip++) {
10743 const float aux =
10744 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
10745 (int) dd->subdomain_count[3])];
10746 if ((fillval == 0 || aux != fillval)
10747 && (missval == 0 || aux != missval)
10748 && fabsf(aux) < 1e14f) {
10749 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10750
10751 } else
10752 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10753 }
10754
10755#pragma omp parallel for default(shared)
10756 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10757 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10758 for (int ip = 0; ip < met->np; ip++) {
10759 const float aux =
10760 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
10761 (int) dd->halo_bnd_count[3])];
10762 if ((fillval == 0 || aux != fillval)
10763 && (missval == 0 || aux != missval)
10764 && fabsf(aux) < 1e14f)
10765 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10766 else
10767 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10768 }
10769 omp_set_dynamic(0);
10770
10771 } else {
10772
10773 /* Copy and check data (ordering: lon, lat, lev)... */
10774 omp_set_dynamic(1);
10775#pragma omp parallel for default(shared)
10776 for (int ip = 0; ip < met->np; ip++)
10777 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10778 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
10779 const float aux =
10780 help[ARRAY_3D
10781 (ix, iy, (int) dd->subdomain_count[2], ip, met->np)];
10782 if ((fillval == 0 || aux != fillval)
10783 && (missval == 0 || aux != missval)
10784 && fabsf(aux) < 1e14f)
10785 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10786 else
10787 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10788 }
10789
10790#pragma omp parallel for default(shared)
10791 for (int ip = 0; ip < met->np; ip++)
10792 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10793 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
10794 const float aux =
10795 help_halo[ARRAY_3D(ix, iy, (int) dd->halo_bnd_count[2], ip,
10796 met->np)];
10797 if ((fillval == 0 || aux != fillval)
10798 && (missval == 0 || aux != missval)
10799 && fabsf(aux) < 1e14f)
10800 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10801 else
10802 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10803 }
10804 omp_set_dynamic(0);
10805 }
10806
10807 /* Free... */
10808 free(help);
10809 free(help_halo);
10810 }
10811
10812 /* Return... */
10813 return 1;
10814}

◆ read_met_ml2pl()

void read_met_ml2pl ( const ctl_t ctl,
const met_t met,
float  var[EX][EY][EP],
const char *  varname 
)

Interpolates meteorological data to specified pressure levels.

This function interpolates meteorological data from model levels to pressure levels. The interpolation is performed in parallel over the spatial grid defined in the meteorological data structure.

Parameters
[in]ctlA pointer to a control structure containing the number of pressure levels (met_np) and the pressure levels themselves (met_p).
[in]metA pointer to a meteorological data structure containing the grid dimensions (nx, ny) and the pressure profile (pl).
[in,out]varA 3D array containing the meteorological variable to be interpolated. On output, this array will contain the interpolated values at the specified pressure levels.
[in]varnameA string representing the name of the meteorological variable being interpolated.

This function performs the following steps:

  • Sets a timer for the operation.
  • Logs the start of the interpolation process with the variable name.
  • Loops over the spatial columns (grid points).
  • For each column, copies the pressure profile.
  • Interpolates the meteorological variable to the specified pressure levels.
  • Copies the interpolated data back into the var array.
Note
The interpolation is performed in parallel using OpenMP.
Author
Lars Hoffmann

Definition at line 11259 of file mptrac.c.

11263 {
11264
11265 double aux[EP], p[EP];
11266
11267 /* Set timer... */
11268 SELECT_TIMER("READ_MET_ML2PL", "METPROC");
11269 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
11270
11271 /* Loop over columns... */
11272#pragma omp parallel for default(shared) private(aux,p) collapse(2)
11273 for (int ix = 0; ix < met->nx; ix++)
11274 for (int iy = 0; iy < met->ny; iy++) {
11275
11276 /* Copy pressure profile... */
11277 for (int ip = 0; ip < met->np; ip++)
11278 p[ip] = met->pl[ix][iy][ip];
11279
11280 /* Interpolate... */
11281 for (int ip = 0; ip < ctl->met_np; ip++) {
11282 double pt = ctl->met_p[ip];
11283 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
11284 pt = p[0];
11285 else if ((pt > p[met->np - 1] && p[1] > p[0])
11286 || (pt < p[met->np - 1] && p[1] < p[0]))
11287 pt = p[met->np - 1];
11288 const int ip2 = locate_irr(p, met->np, pt);
11289 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
11290 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
11291 }
11292
11293 /* Copy data... */
11294 for (int ip = 0; ip < ctl->met_np; ip++)
11295 var[ix][iy][ip] = (float) aux[ip];
11296 }
11297}
Here is the call graph for this function:

◆ read_met_monotonize()

void read_met_monotonize ( const ctl_t ctl,
met_t met 
)

Makes zeta and pressure profiles monotone.

This function ensures that zeta and pressure profiles are monotone increasing and decreasing with altitude. It iterates over each grid point and each level to identify inversions and linearly interpolate between them to maintain monotonicity. The interpolation is performed for both zeta and pressure profiles.

Parameters
ctlA pointer to a control parameter structure.
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the processing time.
  • Iterates over each grid point in parallel using OpenMP.
  • Identifies inversions in both zeta and pressure profiles and interpolates linearly between them to make the profiles monotone increasing.
Note
This function is crucial for maintaining the physical consistency of meteorological profiles, ensuring accurate atmospheric simulations.
Author
Jan Clemens

Definition at line 11301 of file mptrac.c.

11303 {
11304
11305 /* Check parameters... */
11306 if (ctl->advect_vert_coord != 1)
11307 return;
11308
11309 /* Set timer... */
11310 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC");
11311 LOG(2, "Make zeta profiles monotone...");
11312
11313 /* Create monotone zeta profiles... */
11314#pragma omp parallel for default(shared) collapse(2)
11315 for (int i = 0; i < met->nx; i++)
11316 for (int j = 0; j < met->ny; j++) {
11317 int k = 1;
11318
11319 while (k < met->npl) { /* Check if there is an inversion at level k... */
11320 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
11321 /* Find the upper level k+l over the inversion... */
11322 int l = 0;
11323 do {
11324 l++;
11325 }
11326 while ((met->zetal[i][j][k - 1] >=
11327 met->zetal[i][j][k + l]) & (k + l < met->npl));
11328
11329 /* Interpolate linear between the top and bottom
11330 of the inversion... */
11331 float s =
11332 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
11333 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
11334
11335 for (int m = k; m < k + l; m++) {
11336 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
11337 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
11338 }
11339
11340 /* Search for more inversions above the last inversion ... */
11341 k = k + l;
11342 } else {
11343 k++;
11344 }
11345 }
11346 }
11347
11348 /* Create monotone pressure profiles... */
11349#pragma omp parallel for default(shared) collapse(2)
11350 for (int i = 0; i < met->nx; i++)
11351 for (int j = 0; j < met->ny; j++) {
11352 int k = 1;
11353
11354 while (k < met->npl) { /* Check if there is an inversion at level k... */
11355 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
11356
11357 /* Find the upper level k+l over the inversion... */
11358 int l = 0;
11359 do {
11360 l++;
11361 }
11362 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
11363 met->npl));
11364
11365 /* Interpolate linear between the top and bottom
11366 of the inversion... */
11367 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
11368 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
11369
11370 for (int m = k; m < k + l; m++) {
11371 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
11372 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
11373 }
11374
11375 /* Search for more inversions above the last inversion ... */
11376 k += l;
11377 } else {
11378 k++;
11379 }
11380 }
11381 }
11382}

◆ read_met_nc()

int read_met_nc ( const char *  filename,
const ctl_t ctl,
met_t met,
dd_t dd 
)

Reads meteorological data from a NetCDF file and processes it.

This function reads meteorological data from a NetCDF file specified by the filename parameter, using the NetCDF library. It reads grid, surface, and vertical level data, processes the data (including extrapolation, boundary conditions, and downsampling), and calculates various derived meteorological fields such as geopotential heights, potential vorticity, cloud properties, and convective available potential energy (CAPE).

Parameters
filenameA constant character pointer representing the name of the NetCDF file to read the meteorological data from.
ctlA pointer to a ctl_t structure, which contains control parameters for reading and processing the meteorological data.
metA pointer to a met_t structure that will store the meteorological data read and processed from the NetCDF file.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.
Returns
Returns 1 on success, or 0 if the file cannot be opened.
Note
  • The function opens the NetCDF file in read-only mode using nc_open and handles any errors during the file opening process.
  • The function reads grid data, vertical level data, and surface data from the file, and processes the data to calculate additional meteorological parameters.
  • If the file cannot be opened, the function logs a warning and returns 0.
  • It is important to ensure that the NetCDF file contains the expected structure for meteorological data (grid, levels, surface data).
Author
Lars Hoffmann

Definition at line 11386 of file mptrac.c.

11390 {
11391
11392 int ncid;
11393
11394 /* Open file... */
11395#ifdef DD
11396 if (ctl->dd) {
11397 NC(nc_open_par
11398 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
11399 &ncid))
11400 }
11401#else
11402 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
11403 WARN("Cannot open file!");
11404 return 0;
11405 }
11406#endif
11407
11408 /* Set coordinate system of meteo data... */
11409 met->coord_type = ctl->met_coord_type;
11410
11411 /* Read coordinates of meteo data... */
11412 read_met_nc_grid(filename, ncid, ctl, met, dd);
11413
11414 /* Read surface data... */
11415 read_met_nc_surface(ncid, ctl, met, dd);
11416
11417 /* Read meteo data on vertical levels... */
11418 read_met_nc_levels(ncid, ctl, met, dd);
11419
11420 /* Close file... */
11421 NC(nc_close(ncid));
11422
11423 /* Return success... */
11424 return 1;
11425}
void read_met_nc_levels(const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads and processes meteorological level data from NetCDF files with domain decomposition.
Definition: mptrac.c:9988
void read_met_nc_surface(const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads and processes surface meteorological data from NetCDF files with domain decomposition.
Definition: mptrac.c:9850
void read_met_nc_grid(const char *filename, const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads meteorological grid data from NetCDF files with domain decomposition.
Definition: mptrac.c:9663
Here is the call graph for this function:

◆ dd_read_met_nc_grid()

void dd_read_met_nc_grid ( dd_t dd,
const ctl_t ctl,
met_t met,
const int  ncid 
)

Read meteorological grid information and construct the domain-decomposed grid with halo regions.

This routine reads the global longitude and latitude grid from a NetCDF meteorological input file and initializes the domain decomposition used for parallel processing. The global grid is partitioned into zonal and meridional subdomains according to ctl->dd_subdomains_zonal and ctl->dd_subdomains_meridional.

For the current MPI rank, the routine determines the core subdomain in index space and constructs a hyperslab describing the portion of the meteorological grid that must be read from the NetCDF file. The hyperslab is extended with inner halo cells to overlap with neighboring subdomains. For ranks located at the zonal boundaries, additional periodic boundary halos are created.

The function populates the local longitude and latitude arrays in the met_t structure for the subdomain including halos, and stores the hyperslab definitions and halo offsets in the dd_t structure.

Parameters
[out]ddDomain decomposition structure. On return it contains global grid dimensions, hyperslab definitions for the local subdomain, and halo metadata.
[in]ctlControl structure specifying the number of zonal and meridional subdomains and the halo size (dd_subdomains_zonal, dd_subdomains_meridional, dd_halos_size).
[out]metMeteorological grid structure. On return it contains the local longitude and latitude arrays and the grid dimensions (nx, ny, np) of the halo-extended subdomain.
[in]ncidNetCDF file identifier returned by nc_open().
Note
  • Requires MPI when compiled with -DMPI.
  • The domain decomposition is performed in index space; the global grid may therefore have irregular spacing (e.g. Gaussian latitudes).
  • Zonal periodicity is handled by constructing additional boundary halo hyperslabs with appropriate longitude shifts.
Author
Jan Clemens
Lars Hoffmann

Definition at line 11429 of file mptrac.c.

11433 {
11434
11435 int varid;
11436
11437 /* Get the MPI information... */
11438 int rank = 0, size = 1;
11439#ifdef MPI
11440 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
11441 MPI_Comm_size(MPI_COMM_WORLD, &size);
11442#endif
11443
11444 /* Get grid dimensions... */
11445 NC_INQ_DIM("lon", &dd->nx_glob, 0, 0, 0);
11446 NC_INQ_DIM("lat", &dd->ny_glob, 0, 0, 0);
11447
11448 LOG(2, "Number of longitudes: %d", dd->nx_glob);
11449 LOG(2, "Number of latitudes: %d", dd->ny_glob);
11450
11451 /* Check grid... */
11452 if (dd->nx_glob > DD_EX_GLOB || dd->ny_glob > DD_EY_GLOB)
11453 ERRMSG("Global grid is too large!");
11454
11455 if (ctl->dd_subdomains_zonal > dd->nx_glob)
11456 ERRMSG("Too many zonal subdomains for global x grid!");
11457
11458 if (ctl->dd_subdomains_meridional > dd->ny_glob)
11459 ERRMSG("Too many meridional subdomains for global y grid!");
11460
11461 /* Read global longitudes and latitudes... */
11462 NC_GET_DOUBLE("lon", dd->lon_glob, 1);
11463 NC_GET_DOUBLE("lat", dd->lat_glob, 1);
11464
11465 LOG(2, "Longitudes: %g, %g ... %g deg",
11466 dd->lon_glob[0], dd->lon_glob[1], dd->lon_glob[dd->nx_glob - 1]);
11467 LOG(2, "Latitudes: %g, %g ... %g deg",
11468 dd->lat_glob[0], dd->lat_glob[1], dd->lat_glob[dd->ny_glob - 1]);
11469
11470 /* Rank coordinates in DD layout... */
11471 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
11472 const int merid_rank = rank % ctl->dd_subdomains_meridional;
11473
11474 /* Check for edge cases... */
11475 const int left = (zonal_rank == 0);
11476 const int right = (zonal_rank == ctl->dd_subdomains_zonal - 1);
11477 const int top = (merid_rank == 0);
11478 const int bottom = (merid_rank == ctl->dd_subdomains_meridional - 1);
11479
11480 /* Core owned block (without halos)... */
11481 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
11482 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
11483
11484 const int ix0 = zonal_rank * nx_block;
11485 const int iy0 = merid_rank * ny_block;
11486
11487 int nx_core = nx_block;
11488 int ny_core = ny_block;
11489
11490 if (right)
11491 nx_core += dd->nx_glob - ctl->dd_subdomains_zonal * nx_block;
11492 if (bottom)
11493 ny_core += dd->ny_glob - ctl->dd_subdomains_meridional * ny_block;
11494
11495 /* Store core met size first... */
11496 met->nx = nx_core;
11497 met->ny = ny_core;
11498
11499 /* Set hyperslab for core subdomain... */
11500 dd->subdomain_start[0] = 0;
11501 dd->subdomain_start[1] = 0;
11502 dd->subdomain_start[2] = (size_t) iy0;
11503 dd->subdomain_start[3] = (size_t) ix0;
11504
11505 dd->subdomain_count[0] = 1;
11506 dd->subdomain_count[1] = (size_t) met->np;
11507 dd->subdomain_count[2] = (size_t) ny_core;
11508 dd->subdomain_count[3] = (size_t) nx_core;
11509
11510 /* Add inner halos to read window... */
11511 if (!left && !right) {
11512 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
11513 dd->subdomain_count[3] += (size_t) (2 * ctl->dd_halos_size);
11514 } else if (left ^ right) {
11515 dd->subdomain_count[3] += (size_t) ctl->dd_halos_size;
11516 if (!left)
11517 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
11518 }
11519
11520 if (!top && !bottom) {
11521 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
11522 dd->subdomain_count[2] += (size_t) (2 * ctl->dd_halos_size);
11523 } else if (top ^ bottom) {
11524 dd->subdomain_count[2] += (size_t) ctl->dd_halos_size;
11525 if (!top)
11526 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
11527 }
11528
11529 /* Set boundary halo hyperslabs... */
11530 double lon_shift = 0.0;
11531
11532 if (left ^ right) {
11533 dd->halo_bnd_start[0] = 0;
11534 dd->halo_bnd_start[1] = 0;
11535 dd->halo_bnd_start[2] = dd->subdomain_start[2];
11536 dd->halo_bnd_start[3] =
11537 (size_t) (left ? (dd->nx_glob - ctl->dd_halos_size) : 0);
11538
11539 dd->halo_bnd_count[0] = 1;
11540 dd->halo_bnd_count[1] = (size_t) met->np;
11541 dd->halo_bnd_count[2] =
11542 (size_t) met->ny +
11543 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
11544 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
11545
11546 dd->halo_offset_start = left ? (int) dd->halo_bnd_count[3] : 0;
11547 dd->halo_offset_end = left ? 0 : (int) dd->subdomain_count[3];
11548 lon_shift = left ? -360.0 : 360.0;
11549 } else {
11550 dd->halo_bnd_start[0] = 0;
11551 dd->halo_bnd_start[1] = 0;
11552 dd->halo_bnd_start[2] = 0;
11553 dd->halo_bnd_start[3] = 0;
11554
11555 dd->halo_bnd_count[0] = 0;
11556 dd->halo_bnd_count[1] = 0;
11557 dd->halo_bnd_count[2] = 0;
11558 dd->halo_bnd_count[3] = 0;
11559
11560 dd->halo_offset_start = 0;
11561 dd->halo_offset_end = 0;
11562 }
11563
11564 /* Focus on subdomain latitudes... */
11565 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
11566 met->lat[iy] = dd->lat_glob[(int) dd->subdomain_start[2] + iy];
11567
11568 /* Focus on subdomain longitudes... */
11569 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
11570 met->lon[ix + dd->halo_offset_start] =
11571 dd->lon_glob[(int) dd->subdomain_start[3] + ix];
11572
11573 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
11574 met->lon[ix + dd->halo_offset_end] =
11575 dd->lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
11576
11577 /* Reset halo-extended grid dimensions... */
11578 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
11579 met->ny = (int) dd->subdomain_count[2];
11580
11581 LOG(2, "Define subdomain properties.");
11582 LOG(2, "MPI information: Rank %d, Size %d", rank, size);
11583 LOG(2, "Edge position: l=%d,r=%d,t=%d,b=%d", left, right, top, bottom);
11584 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d",
11585 met->nx, met->ny, met->np);
11586 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
11587 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
11588 (int) dd->halo_bnd_count[1]);
11589 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
11590 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
11591 (int) dd->subdomain_count[1]);
11592 LOG(2, "Subdomain start: nx %ld ny %ld np %ld",
11593 dd->subdomain_start[3], dd->subdomain_start[2], dd->subdomain_start[1]);
11594 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld",
11595 dd->halo_bnd_start[3], dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
11596 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
11597 LOG(2, "%d Subdomain longitudes: %g, %g ... %g deg",
11598 rank, met->lon[0], met->lon[1], met->lon[met->nx - 1]);
11599 LOG(2, "%d Subdomain latitudes: %g, %g ... %g deg",
11600 rank, met->lat[0], met->lat[1], met->lat[met->ny - 1]);
11601}
#define DD_EY_GLOB
Maximum number of latitudes of global meteo data.
Definition: mptrac.h:633
#define DD_EX_GLOB
Maximum number of longitudes of global meteo data.
Definition: mptrac.h:628
int nx_glob
Number of global longitudes.
Definition: mptrac.h:4030
double lon_glob[DD_EX_GLOB]
Longitudes of the global grid [deg].
Definition: mptrac.h:4036
double lat_glob[DD_EY_GLOB]
Latitudes of the global grid [deg].
Definition: mptrac.h:4039
int ny_glob
Number of global latitudes.
Definition: mptrac.h:4033

◆ read_met_pbl()

void read_met_pbl ( const ctl_t ctl,
met_t met 
)

Computes the planetary boundary layer (PBL) pressure based on meteorological data.

This function determines the PBL pressure for each grid point using one of four methods: 0. Read PBL pressure from meteo data file.

  1. Read PBL heights from meteo data file and convert to pressure.
  2. Determine PBL pressure based on bulk Richardson number criterion.
  3. Determine PBL pressure Based on potential temperature difference. The calculated PBL height is constrained by user-defined minimum and maximum limits.
Parameters
[in]ctlPointer to the control structure (ctl_t), which contains parameters controlling the PBL calculation.
[in,out]metPointer to the meteorological data structure (met_t), which contains grid and atmospheric data. The met->pbl array is updated with the calculated PBL pressure.

Method 0 (Precomputed PBL pressure from file):

  • Read PBL pressure from meteo data file.

Method 1 (Precomputed PBL height from file):

  • Read PBL height from meteo data file.
  • Interpolates the PBL pressure using the geopotential heights from the meteo file.

Method 2 (Richardson number criterion):

  • Implements a method based on the bulk Richardson number (critical value: Ri = 0.25).
  • Iteratively evaluates vertical levels, calculating wind shear, and thermal gradients, until the Richardson number exceeds the critical threshold.
  • Interpolates between levels to find the precise height.

Method 3 (Potential temperature difference):

  • Computes the PBL height as the altitude where the potential temperature exceeds the surface value by 2 K.
  • Interpolates between levels to find the precise height.

Final Adjustments:

  • Ensures the PBL height respects user-defined minimum and maximum thresholds.
Note
Method 2 is a standard method for estimating PBL depths, but the current implementation seems to underestimate PBL depths compared to ECMWF PBL data or Method 3. Therefore, Method 3, is selected by default. If PBL heights are available from the meteo data files, it is recommended to select Method 1.
Author
Lars Hoffmann

Definition at line 11605 of file mptrac.c.

11607 {
11608
11609 /* Set timer... */
11610 SELECT_TIMER("READ_MET_PBL", "METPROC");
11611 LOG(2, "Calculate planetary boundary layer...");
11612
11613 /* Convert PBL height from meteo file to pressure... */
11614 if (ctl->met_pbl == 1) {
11615
11616 /* Loop over grid points... */
11617#pragma omp parallel for default(shared) collapse(2)
11618 for (int ix = 0; ix < met->nx; ix++)
11619 for (int iy = 0; iy < met->ny; iy++) {
11620
11621 /* Get pressure at top of PBL... */
11622 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
11623 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
11624 met->pbl[ix][iy] =
11625 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
11626 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
11627 }
11628 }
11629
11630 /* Determine PBL based on Richardson number... */
11631 else if (ctl->met_pbl == 2) {
11632
11633 /* Parameters used to estimate the height of the PBL
11634 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
11635 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
11636
11637 /* Loop over grid points... */
11638#pragma omp parallel for default(shared) collapse(2)
11639 for (int ix = 0; ix < met->nx; ix++)
11640 for (int iy = 0; iy < met->ny; iy++) {
11641
11642 /* Set bottom level of PBL... */
11643 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
11644
11645 /* Find lowest level near the bottom... */
11646 int ip;
11647 for (ip = 1; ip < met->np; ip++)
11648 if (met->p[ip] < pbl_bot)
11649 break;
11650
11651 /* Get near surface data... */
11652 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
11653 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
11654 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
11655
11656 /* Init... */
11657 double rib_old = 0;
11658
11659 /* Loop over levels... */
11660 for (; ip < met->np; ip++) {
11661
11662 /* Get squared horizontal wind speed... */
11663 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
11664 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
11665 vh2 = MAX(vh2, SQR(umin));
11666
11667 /* Calculate bulk Richardson number... */
11668 const double rib =
11669 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
11670 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
11671 met->h2o[ix][iy][ip]) - tvs) / vh2;
11672
11673 /* Check for critical value... */
11674 if (rib >= rib_crit) {
11675 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
11676 rib, met->p[ip], rib_crit));
11677 if (met->pbl[ix][iy] > pbl_bot)
11678 met->pbl[ix][iy] = (float) pbl_bot;
11679 break;
11680 }
11681
11682 /* Save Richardson number... */
11683 rib_old = rib;
11684 }
11685 }
11686 }
11687
11688 /* Determine PBL based on potential temperature... */
11689 if (ctl->met_pbl == 3) {
11690
11691 /* Parameters used to estimate the height of the PBL
11692 (following HYSPLIT model)... */
11693 const double dtheta = 2.0, zmin = 0.1;
11694
11695 /* Loop over grid points... */
11696#pragma omp parallel for default(shared) collapse(2)
11697 for (int ix = 0; ix < met->nx; ix++)
11698 for (int iy = 0; iy < met->ny; iy++) {
11699
11700 /* Potential temperature at the surface... */
11701 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
11702
11703 /* Find topmost level where theta exceeds surface value by 2 K... */
11704 int ip;
11705 for (ip = met->np - 2; ip > 0; ip--)
11706 if (met->p[ip] >= 300.)
11707 if (met->p[ip] > met->ps[ix][iy]
11708 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
11709 break;
11710
11711 /* Interpolate... */
11712 met->pbl[ix][iy]
11713 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
11714 met->p[ip + 1],
11715 THETA(met->p[ip], met->t[ix][iy][ip]),
11716 met->p[ip], theta0 + dtheta));
11717
11718 /* Check minimum value... */
11719 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
11720 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
11721 met->pbl[ix][iy] = (float) pbl_min;
11722 }
11723 }
11724
11725 /* Loop over grid points... */
11726#pragma omp parallel for default(shared) collapse(2)
11727 for (int ix = 0; ix < met->nx; ix++)
11728 for (int iy = 0; iy < met->ny; iy++) {
11729
11730 /* Check minimum value... */
11731 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
11732 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
11733
11734 /* Check maximum value... */
11735 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
11736 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
11737 }
11738}
Here is the call graph for this function:

◆ read_met_periodic()

void read_met_periodic ( met_t met)

Applies periodic boundary conditions to meteorological data along longitudinal axis.

This function applies periodic boundary conditions to meteorological data along the longitudinal axis. It checks if the difference between the last and first longitudes and the difference between the second and first longitudes are approximately equal to 360 degrees, indicating periodicity. If the condition is met, the function increases the longitude counter, sets the longitude value for the new grid point, and copies meteorological data from the first grid point to the last grid point to ensure periodicity.

Parameters
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets timer for performance monitoring.
  • Checks if the difference between the last and first longitudes and the difference between the second and first longitudes are approximately equal to 360 degrees, indicating periodicity.
  • If periodicity is confirmed:
    • Increases the longitude counter.
    • Sets the longitude value for the new grid point by adding the difference between the second and first longitudes to the longitude of the penultimate grid point.
    • Copies meteorological data from the first grid point to the last grid point to ensure periodicity:
      • Surface variables (e.g., pressure, temperature, wind speed, land-sea mask, sea surface temperature) are copied.
      • Meteorological variables at each pressure level are copied.
      • Meteorological variables at each hybrid pressure level are copied.
Note
This function is useful for generating continuous meteorological fields over a periodic domain, which is common in atmospheric modeling, especially for global simulations.
Author
Lars Hoffmann

Definition at line 11742 of file mptrac.c.

11743 {
11744
11745 /* Set timer... */
11746 SELECT_TIMER("READ_MET_PERIODIC", "METPROC");
11747 LOG(2, "Apply periodic boundary conditions...");
11748
11749 /* Check longitudes... */
11750 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
11751 + met->lon[1] - met->lon[0] - 360) < 0.01))
11752 return;
11753
11754 /* Increase longitude counter... */
11755 if ((++met->nx) >= EX)
11756 ERRMSG("Cannot create periodic boundary conditions!");
11757
11758 /* Set longitude... */
11759 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
11760
11761 /* Loop over latitudes and pressure levels... */
11762#pragma omp parallel for default(shared)
11763 for (int iy = 0; iy < met->ny; iy++) {
11764 met->ps[met->nx - 1][iy] = met->ps[0][iy];
11765 met->zs[met->nx - 1][iy] = met->zs[0][iy];
11766 met->ts[met->nx - 1][iy] = met->ts[0][iy];
11767 met->us[met->nx - 1][iy] = met->us[0][iy];
11768 met->vs[met->nx - 1][iy] = met->vs[0][iy];
11769 met->ess[met->nx - 1][iy] = met->ess[0][iy];
11770 met->nss[met->nx - 1][iy] = met->nss[0][iy];
11771 met->shf[met->nx - 1][iy] = met->shf[0][iy];
11772 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
11773 met->sst[met->nx - 1][iy] = met->sst[0][iy];
11774 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
11775 met->cape[met->nx - 1][iy] = met->cape[0][iy];
11776 met->cin[met->nx - 1][iy] = met->cin[0][iy];
11777 for (int ip = 0; ip < met->np; ip++) {
11778 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
11779 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
11780 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
11781 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
11782 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
11783 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
11784 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
11785 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
11786 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
11787 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
11788 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
11789 }
11790 for (int ip = 0; ip < met->npl; ip++) {
11791 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
11792 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
11793 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
11794 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
11795 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
11796 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
11797 }
11798 }
11799}

◆ read_met_polar_winds()

void read_met_polar_winds ( met_t met)

Applies a fix for polar winds in meteorological data.

This function applies a fix for polar winds in meteorological data, particularly focusing on the u and v wind components. It checks if the latitudes at the top and bottom of the grid are close to the poles. If so, it transforms the winds at 89-degree latitude into Cartesian coordinates, takes their mean, and replaces the winds at 90-degree latitude with this mean, effectively fixing the unrealistic behavior of winds at the poles.

Parameters
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets a timer for performance monitoring.
  • Checks if the latitudes at the top and bottom of the grid are close to the poles (within 0.001 degree latitude of the poles).
  • For each hemisphere (north and south):
    • Sets latitude indices for 89 degrees and 90 degrees.
    • Determines the sign of longitude adjustments based on the hemisphere.
    • Constructs lookup tables for cosine and sine of longitudes.
    • Loops over pressure levels and performs the following operations:
      • Transforms u and v wind components at 89 degrees latitude into Cartesian coordinates and calculates their mean.
      • Replaces u and v wind components at 90 degrees latitude with the calculated mean, effectively fixing the polar winds.
Note
This function is useful for correcting unrealistic behavior of winds near the poles in meteorological data, which can affect various atmospheric simulations.
Based on a Python code provided by Jens-Uwe Grooß.
Author
Lars Hoffmann

Definition at line 11803 of file mptrac.c.

11804 {
11805
11806 /* Set timer... */
11807 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC");
11808 LOG(2, "Apply fix for polar winds...");
11809
11810 if (met->coord_type != 0)
11811 return;
11812
11813 /* Check latitudes... */
11814 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
11815 return;
11816
11817 /* Loop over hemispheres... */
11818 for (int ihem = 0; ihem < 2; ihem++) {
11819
11820 /* Set latitude indices... */
11821 int i89 = 1, i90 = 0, sign = 1;
11822 if (ihem == 1) {
11823 i89 = met->ny - 2;
11824 i90 = met->ny - 1;
11825 }
11826 if (met->lat[i90] < 0)
11827 sign = -1;
11828
11829 /* Look-up table of cosinus and sinus... */
11830 double clon[EX], slon[EX];
11831#pragma omp parallel for default(shared)
11832 for (int ix = 0; ix < met->nx; ix++) {
11833 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
11834 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
11835 }
11836
11837 /* Loop over levels... */
11838#pragma omp parallel for default(shared)
11839 for (int ip = 0; ip < met->np; ip++) {
11840
11841 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
11842 double vel89x = 0, vel89y = 0;
11843 for (int ix = 0; ix < met->nx; ix++) {
11844 vel89x +=
11845 (met->u[ix][i89][ip] * clon[ix] -
11846 met->v[ix][i89][ip] * slon[ix]) / met->nx;
11847 vel89y +=
11848 (met->u[ix][i89][ip] * slon[ix] +
11849 met->v[ix][i89][ip] * clon[ix]) / met->nx;
11850 }
11851
11852 /* Replace 90 degree winds by 89 degree mean... */
11853 for (int ix = 0; ix < met->nx; ix++) {
11854 met->u[ix][i90][ip]
11855 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
11856 met->v[ix][i90][ip]
11857 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
11858 }
11859 }
11860 }
11861}

◆ read_met_pv()

void read_met_pv ( met_t met)

Calculates potential vorticity (PV) from meteorological data.

This function calculates the potential vorticity (PV) from the provided meteorological data. It employs finite difference methods to estimate gradients of temperature, wind components, and pressure in longitude, latitude, and pressure dimensions. These gradients are then used to compute PV at each grid point. Additionally, a fix for polar regions is applied to ensure smoothness of PV values in these regions.

Parameters
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets a timer for performance monitoring.
  • Computes powers for pressure calculation.
  • Loops over grid points in longitude:
    • Sets latitude indices.
    • Loops over grid points in latitude:
      • Sets indices and auxiliary variables.
      • Loops over pressure levels:
        • Computes gradients in longitude, latitude, and pressure.
        • Calculates PV using computed gradients.
  • Applies a fix for polar regions to ensure smoothness of PV values.
Note
Potential vorticity is a fundamental quantity in atmospheric dynamics, representing the potential of a fluid parcel to rotate due to changes in pressure, temperature, and wind fields.
Based on a Python code by Mathew Barlow (https://github.com/mathewbarlow/potential-vorticity).
Author
Lars Hoffmann

Definition at line 11865 of file mptrac.c.

11866 {
11867
11868 double pows[EP];
11869
11870 /* Set timer... */
11871 SELECT_TIMER("READ_MET_PV", "METPROC");
11872 LOG(2, "Calculate potential vorticity...");
11873
11874 /* Set powers... */
11875#pragma omp parallel for default(shared)
11876 for (int ip = 0; ip < met->np; ip++)
11877 pows[ip] = pow(1000. / met->p[ip], KAPPA);
11878
11879 /* Loop over grid points... */
11880#pragma omp parallel for default(shared)
11881 for (int ix = 0; ix < met->nx; ix++) {
11882
11883 /* Set indices... */
11884 const int ix0 = MAX(ix - 1, 0);
11885 const int ix1 = MIN(ix + 1, met->nx - 1);
11886
11887 /* Loop over grid points... */
11888 for (int iy = 0; iy < met->ny; iy++) {
11889
11890 /* Set indices... */
11891 const int iy0 = MAX(iy - 1, 0);
11892 const int iy1 = MIN(iy + 1, met->ny - 1);
11893
11894 /* Set auxiliary variables... */
11895 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
11896 double dx, dy, c0, c1, cr, vort;
11897
11898 // Calculate potential vorticity..
11899 if (met->coord_type == 0) { // coords are lat/lon
11900 dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
11901 dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
11902 c0 = cos(DEG2RAD(met->lat[iy0]));
11903 c1 = cos(DEG2RAD(met->lat[iy1]));
11904 cr = cos(DEG2RAD(latr));
11905 vort = 2 * OMEGA_EARTH * sin(DEG2RAD(latr));
11906 } else { // coords are in meters
11907 dx = met->lon[ix1] - met->lon[ix0];
11908 dy = met->lat[iy1] - met->lat[iy0];
11909
11910 c0 = 1.0;
11911 c1 = 1.0;
11912 cr = 1.0;
11913
11914 vort = 2 * OMEGA_EARTH * sin(latr / (RE * 1000));
11915 }
11916
11917 /* Loop over grid points... */
11918 for (int ip = 0; ip < met->np; ip++) {
11919
11920 /* Get gradients in longitude... */
11921 const double dtdx
11922 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
11923 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
11924
11925 /* Get gradients in latitude... */
11926 const double dtdy
11927 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
11928 const double dudy
11929 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
11930
11931 /* Set indices... */
11932 const int ip0 = MAX(ip - 1, 0);
11933 const int ip1 = MIN(ip + 1, met->np - 1);
11934
11935 /* Get gradients in pressure... */
11936 double dtdp, dudp, dvdp;
11937 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
11938 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
11939 if (ip != ip0 && ip != ip1) {
11940 double denom = dp0 * dp1 * (dp0 + dp1);
11941 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
11942 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
11943 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
11944 / denom;
11945 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
11946 - dp1 * dp1 * met->u[ix][iy][ip0]
11947 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
11948 / denom;
11949 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
11950 - dp1 * dp1 * met->v[ix][iy][ip0]
11951 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
11952 / denom;
11953 } else {
11954 const double denom = dp0 + dp1;
11955 dtdp =
11956 (met->t[ix][iy][ip1] * pows[ip1] -
11957 met->t[ix][iy][ip0] * pows[ip0]) / denom;
11958 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
11959 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
11960 }
11961
11962 /* Calculate PV... */
11963 met->pv[ix][iy][ip] = (float)
11964 (1e6 * G0 *
11965 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
11966 }
11967 }
11968 }
11969
11970 /* Fix for polar regions... */
11971#pragma omp parallel for default(shared)
11972 for (int ix = 0; ix < met->nx; ix++)
11973 for (int ip = 0; ip < met->np; ip++) {
11974 met->pv[ix][0][ip]
11975 = met->pv[ix][1][ip]
11976 = met->pv[ix][2][ip];
11977 met->pv[ix][met->ny - 1][ip]
11978 = met->pv[ix][met->ny - 2][ip]
11979 = met->pv[ix][met->ny - 3][ip];
11980 }
11981}
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:839
#define OMEGA_EARTH
Angular velocity of Earth [s^-1].
Definition: mptrac.h:329
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:818

◆ read_met_ozone()

void read_met_ozone ( met_t met)

Calculates the total column ozone from meteorological ozone data.

This function calculates the total column ozone from the provided meteorological ozone data. It integrates ozone concentrations over altitude to obtain the column ozone density. The result is then converted to Dobson units, which represent the thickness of the ozone layer if compressed into one layer at standard temperature and pressure.

Parameters
metA pointer to a structure containing meteorological ozone data.

The function performs the following steps:

  • Sets a timer for performance monitoring.
  • Loops over columns in longitude and latitude:
    • Integrates ozone concentrations over altitude.
    • Converts the integrated ozone density to Dobson units.
Note
Total column ozone is a critical metric for understanding ozone distribution in the atmosphere, with implications for climate, air quality, and UV radiation.
Author
Lars Hoffmann

Definition at line 11985 of file mptrac.c.

11986 {
11987
11988 /* Set timer... */
11989 SELECT_TIMER("READ_MET_OZONE", "METPROC");
11990 LOG(2, "Calculate total column ozone...");
11991
11992 /* Loop over columns... */
11993#pragma omp parallel for default(shared) collapse(2)
11994 for (int ix = 0; ix < met->nx; ix++)
11995 for (int iy = 0; iy < met->ny; iy++) {
11996
11997 /* Integrate... */
11998 double cd = 0;
11999 for (int ip = 1; ip < met->np; ip++)
12000 if (met->p[ip - 1] <= met->ps[ix][iy]) {
12001 const double vmr =
12002 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
12003 const double dp = met->p[ip - 1] - met->p[ip];
12004 cd += vmr * MO3 / MA * dp * 1e2 / G0;
12005 }
12006
12007 /* Convert to Dobson units... */
12008 met->o3c[ix][iy] = (float) (cd / DOBSON_UNIT);
12009 }
12010}
#define DOBSON_UNIT
Ozone column mass corresponding to one Dobson unit [kg/m^2].
Definition: mptrac.h:334

◆ read_met_sample()

void read_met_sample ( const ctl_t ctl,
met_t met 
)

Downsamples meteorological data based on specified parameters.

This function downsamples meteorological data based on the provided control parameters. It reduces the resolution of meteorological data by averaging over specified intervals in longitude, latitude, and altitude.

Parameters
ctlA pointer to a structure containing control parameters for downsampling.
metA pointer to a structure containing meteorological data to be downsampled.

The function performs the following steps:

  • Checks if downsampling parameters are set to a value less than or equal to 1, if so, returns without downsampling.
  • Sets a timer for performance monitoring.
  • Allocates memory for a temporary meteorological data structure.
  • Copies metadata from the original structure to the temporary structure.
  • Performs downsampling by smoothing over specified intervals:
    • Computes weighted averages over the specified intervals.
    • Updates the temporary structure with the smoothed values.
  • Downsamples the smoothed data:
    • Updates longitude and latitude arrays with downsampled values.
    • Stores downsampled meteorological variables in the original structure.
  • Frees memory allocated for the temporary structure.
Note
Downsampling meteorological data can be useful for reducing computational cost while preserving essential features for modeling and analysis.
Author
Lars Hoffmann

Definition at line 12014 of file mptrac.c.

12016 {
12017
12018 met_t *help;
12019
12020 /* Check parameters... */
12021 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
12022 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
12023 return;
12024
12025 /* Set timer... */
12026 SELECT_TIMER("READ_MET_SAMPLE", "METPROC");
12027 LOG(2, "Downsampling of meteo data...");
12028
12029 /* Allocate... */
12030 ALLOC(help, met_t, 1);
12031
12032 /* Copy data... */
12033 help->nx = met->nx;
12034 help->ny = met->ny;
12035 help->np = met->np;
12036 memcpy(help->lon, met->lon, sizeof(met->lon));
12037 memcpy(help->lat, met->lat, sizeof(met->lat));
12038 memcpy(help->p, met->p, sizeof(met->p));
12039
12040 /* Smoothing... */
12041 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
12042 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
12043 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
12044 help->ps[ix][iy] = 0;
12045 help->zs[ix][iy] = 0;
12046 help->ts[ix][iy] = 0;
12047 help->us[ix][iy] = 0;
12048 help->vs[ix][iy] = 0;
12049 help->ess[ix][iy] = 0;
12050 help->nss[ix][iy] = 0;
12051 help->shf[ix][iy] = 0;
12052 help->lsm[ix][iy] = 0;
12053 help->sst[ix][iy] = 0;
12054 help->pbl[ix][iy] = 0;
12055 help->cape[ix][iy] = 0;
12056 help->cin[ix][iy] = 0;
12057 help->t[ix][iy][ip] = 0;
12058 help->u[ix][iy][ip] = 0;
12059 help->v[ix][iy][ip] = 0;
12060 help->w[ix][iy][ip] = 0;
12061 help->h2o[ix][iy][ip] = 0;
12062 help->o3[ix][iy][ip] = 0;
12063 help->lwc[ix][iy][ip] = 0;
12064 help->rwc[ix][iy][ip] = 0;
12065 help->iwc[ix][iy][ip] = 0;
12066 help->swc[ix][iy][ip] = 0;
12067 help->cc[ix][iy][ip] = 0;
12068 float wsum = 0;
12069 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
12070 ix2++) {
12071 int ix3 = ix2;
12072 if (ix3 < 0)
12073 ix3 += met->nx;
12074 else if (ix3 >= met->nx)
12075 ix3 -= met->nx;
12076
12077 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
12078 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
12079 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
12080 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
12081 const float w =
12082 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
12083 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
12084 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
12085 help->ps[ix][iy] += w * met->ps[ix3][iy2];
12086 help->zs[ix][iy] += w * met->zs[ix3][iy2];
12087 help->ts[ix][iy] += w * met->ts[ix3][iy2];
12088 help->us[ix][iy] += w * met->us[ix3][iy2];
12089 help->vs[ix][iy] += w * met->vs[ix3][iy2];
12090 help->ess[ix][iy] += w * met->ess[ix3][iy2];
12091 help->nss[ix][iy] += w * met->nss[ix3][iy2];
12092 help->shf[ix][iy] += w * met->shf[ix3][iy2];
12093 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
12094 help->sst[ix][iy] += w * met->sst[ix3][iy2];
12095 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
12096 help->cape[ix][iy] += w * met->cape[ix3][iy2];
12097 help->cin[ix][iy] += w * met->cin[ix3][iy2];
12098 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
12099 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
12100 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
12101 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
12102 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
12103 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
12104 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
12105 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
12106 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
12107 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
12108 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
12109 wsum += w;
12110 }
12111 }
12112 help->ps[ix][iy] /= wsum;
12113 help->zs[ix][iy] /= wsum;
12114 help->ts[ix][iy] /= wsum;
12115 help->us[ix][iy] /= wsum;
12116 help->vs[ix][iy] /= wsum;
12117 help->ess[ix][iy] /= wsum;
12118 help->nss[ix][iy] /= wsum;
12119 help->shf[ix][iy] /= wsum;
12120 help->lsm[ix][iy] /= wsum;
12121 help->sst[ix][iy] /= wsum;
12122 help->pbl[ix][iy] /= wsum;
12123 help->cape[ix][iy] /= wsum;
12124 help->cin[ix][iy] /= wsum;
12125 help->t[ix][iy][ip] /= wsum;
12126 help->u[ix][iy][ip] /= wsum;
12127 help->v[ix][iy][ip] /= wsum;
12128 help->w[ix][iy][ip] /= wsum;
12129 help->h2o[ix][iy][ip] /= wsum;
12130 help->o3[ix][iy][ip] /= wsum;
12131 help->lwc[ix][iy][ip] /= wsum;
12132 help->rwc[ix][iy][ip] /= wsum;
12133 help->iwc[ix][iy][ip] /= wsum;
12134 help->swc[ix][iy][ip] /= wsum;
12135 help->cc[ix][iy][ip] /= wsum;
12136 }
12137 }
12138 }
12139
12140 /* Downsampling... */
12141 met->nx = 0;
12142 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
12143 met->lon[met->nx] = help->lon[ix];
12144 met->ny = 0;
12145 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
12146 met->lat[met->ny] = help->lat[iy];
12147 met->ps[met->nx][met->ny] = help->ps[ix][iy];
12148 met->zs[met->nx][met->ny] = help->zs[ix][iy];
12149 met->ts[met->nx][met->ny] = help->ts[ix][iy];
12150 met->us[met->nx][met->ny] = help->us[ix][iy];
12151 met->vs[met->nx][met->ny] = help->vs[ix][iy];
12152 met->ess[met->nx][met->ny] = help->ess[ix][iy];
12153 met->nss[met->nx][met->ny] = help->nss[ix][iy];
12154 met->shf[met->nx][met->ny] = help->shf[ix][iy];
12155 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
12156 met->sst[met->nx][met->ny] = help->sst[ix][iy];
12157 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
12158 met->cape[met->nx][met->ny] = help->cape[ix][iy];
12159 met->cin[met->nx][met->ny] = help->cin[ix][iy];
12160 met->np = 0;
12161 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
12162 met->p[met->np] = help->p[ip];
12163 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
12164 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
12165 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
12166 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
12167 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
12168 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
12169 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
12170 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
12171 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
12172 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
12173 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
12174 met->np++;
12175 }
12176 met->ny++;
12177 }
12178 met->nx++;
12179 }
12180
12181 /* Free... */
12182 free(help);
12183}

◆ read_met_tropo()

void read_met_tropo ( const ctl_t ctl,
const clim_t clim,
met_t met 
)

Calculates the tropopause and related meteorological variables based on various methods and stores the results in the meteorological data structure.

This function calculates the tropopause and related meteorological variables using different methods specified by the control parameters. The calculated tropopause pressure is stored in the provided meteorological data structure.

Parameters
ctlA pointer to a structure containing control parameters.
climA pointer to the climatological data structure.
metA pointer to the meteorological data structure to store the calculated tropopause pressure and related variables.

The function performs the following steps:

  • Sets a timer for performance monitoring.
  • Retrieves altitude and pressure profiles from the meteorological data structure.
  • Depending on the control parameters (ctl->met_tropo), it calculates the tropopause using one of the following methods:
    • If ctl->met_tropo == 0, it does not calculate the tropopause and assigns NaN values to the tropopause pressure.
    • If ctl->met_tropo == 1, it uses tropopause climatology to estimate the tropopause pressure based on latitude and time.
    • If ctl->met_tropo == 2, it calculates the tropopause based on the cold point method, finding the altitude where the temperature is at a minimum.
    • If ctl->met_tropo == 3 or ctl->met_tropo == 4, it calculates the tropopause using the WMO definition, which involves identifying a sharp temperature lapse rate between two pressure levels.
    • If ctl->met_tropo == 5, it calculates the dynamical tropopause based on potential vorticity and potential temperature profiles.
  • Interpolates temperature, geopotential height, and water vapor content to the tropopause pressure level using spatial interpolation.
  • Stores the interpolated values in the meteorological data structure.
Note
The function supports parallelization using OpenMP directives to improve performance.
Author
Lars Hoffmann

Definition at line 12187 of file mptrac.c.

12190 {
12191
12192 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
12193 th2[200], z[EP], z2[200];
12194
12195 /* Set timer... */
12196 SELECT_TIMER("READ_MET_TROPO", "METPROC");
12197 LOG(2, "Calculate tropopause...");
12198
12199 /* Get altitude and pressure profiles... */
12200#pragma omp parallel for default(shared)
12201 for (int iz = 0; iz < met->np; iz++)
12202 z[iz] = Z(met->p[iz]);
12203#pragma omp parallel for default(shared)
12204 for (int iz = 0; iz <= 190; iz++) {
12205 z2[iz] = 4.5 + 0.1 * iz;
12206 p2[iz] = P(z2[iz]);
12207 }
12208
12209 /* Do not calculate tropopause... */
12210 if (ctl->met_tropo == 0)
12211#pragma omp parallel for default(shared) collapse(2)
12212 for (int ix = 0; ix < met->nx; ix++)
12213 for (int iy = 0; iy < met->ny; iy++)
12214 met->pt[ix][iy] = NAN;
12215
12216 /* Use tropopause climatology... */
12217 else if (ctl->met_tropo == 1) {
12218 if (met->coord_type != 0)
12219 ERRMSG("Only lat/lon grid supported");
12220#pragma omp parallel for default(shared) collapse(2)
12221 for (int ix = 0; ix < met->nx; ix++)
12222 for (int iy = 0; iy < met->ny; iy++)
12223 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
12224 }
12225
12226 /* Use cold point... */
12227 else if (ctl->met_tropo == 2) {
12228
12229 /* Loop over grid points... */
12230#pragma omp parallel for default(shared) private(t,t2) collapse(2)
12231 for (int ix = 0; ix < met->nx; ix++)
12232 for (int iy = 0; iy < met->ny; iy++) {
12233
12234 /* Interpolate temperature profile... */
12235 for (int iz = 0; iz < met->np; iz++)
12236 t[iz] = met->t[ix][iy][iz];
12237 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
12238
12239 /* Find minimum... */
12240 int iz = (int) gsl_stats_min_index(t2, 1, 171);
12241 if (iz > 0 && iz < 170)
12242 met->pt[ix][iy] = (float) p2[iz];
12243 else
12244 met->pt[ix][iy] = NAN;
12245 }
12246 }
12247
12248 /* Use WMO definition... */
12249 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
12250
12251 /* Loop over grid points... */
12252#pragma omp parallel for default(shared) private(t,t2) collapse(2)
12253 for (int ix = 0; ix < met->nx; ix++)
12254 for (int iy = 0; iy < met->ny; iy++) {
12255
12256 /* Interpolate temperature profile... */
12257 int iz;
12258 for (iz = 0; iz < met->np; iz++)
12259 t[iz] = met->t[ix][iy][iz];
12260 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
12261
12262 /* Find 1st tropopause... */
12263 met->pt[ix][iy] = NAN;
12264 for (iz = 0; iz <= 170; iz++) {
12265 int found = 1;
12266 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
12267 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
12268 found = 0;
12269 break;
12270 }
12271 if (found) {
12272 if (iz > 0 && iz < 170)
12273 met->pt[ix][iy] = (float) p2[iz];
12274 break;
12275 }
12276 }
12277
12278 /* Find 2nd tropopause... */
12279 if (ctl->met_tropo == 4) {
12280 met->pt[ix][iy] = NAN;
12281 for (; iz <= 170; iz++) {
12282 int found = 1;
12283 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
12284 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
12285 found = 0;
12286 break;
12287 }
12288 if (found)
12289 break;
12290 }
12291 for (; iz <= 170; iz++) {
12292 int found = 1;
12293 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
12294 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
12295 found = 0;
12296 break;
12297 }
12298 if (found) {
12299 if (iz > 0 && iz < 170)
12300 met->pt[ix][iy] = (float) p2[iz];
12301 break;
12302 }
12303 }
12304 }
12305 }
12306 }
12307
12308 /* Use dynamical tropopause... */
12309 else if (ctl->met_tropo == 5) {
12310
12311 /* Loop over grid points... */
12312#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
12313 for (int ix = 0; ix < met->nx; ix++)
12314 for (int iy = 0; iy < met->ny; iy++) {
12315
12316 /* Interpolate potential vorticity profile... */
12317 for (int iz = 0; iz < met->np; iz++)
12318 pv[iz] = met->pv[ix][iy][iz];
12319 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
12320
12321 /* Interpolate potential temperature profile... */
12322 for (int iz = 0; iz < met->np; iz++)
12323 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
12324 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
12325
12326 /* Find dynamical tropopause... */
12327 met->pt[ix][iy] = NAN;
12328 for (int iz = 0; iz <= 170; iz++)
12329 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
12330 || th2[iz] >= ctl->met_tropo_theta) {
12331 if (iz > 0 && iz < 170)
12332 met->pt[ix][iy] = (float) p2[iz];
12333 break;
12334 }
12335 }
12336 }
12337
12338 else
12339 ERRMSG("Cannot calculate tropopause!");
12340
12341 /* Interpolate temperature, geopotential height, and water vapor... */
12342#pragma omp parallel for default(shared) collapse(2)
12343 for (int ix = 0; ix < met->nx; ix++)
12344 for (int iy = 0; iy < met->ny; iy++) {
12345 double h2ot, tt, zt;
12347 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
12348 met->lat[iy], &tt, ci, cw, 1);
12349 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
12350 met->lat[iy], &zt, ci, cw, 0);
12351 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
12352 met->lat[iy], &h2ot, ci, cw, 0);
12353 met->tt[ix][iy] = (float) tt;
12354 met->zt[ix][iy] = (float) zt;
12355 met->h2ot[ix][iy] = (float) h2ot;
12356 }
12357}
void spline(const double *x, const double *y, const int n, const double *x2, double *y2, const int n2, const int method)
Performs spline interpolation or linear interpolation.
Definition: mptrac.c:12567
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:1331
Here is the call graph for this function:

◆ read_obs()

void read_obs ( const char *  filename,
const ctl_t ctl,
double *  rt,
double *  rz,
double *  rlon,
double *  rlat,
double *  robs,
int *  nobs 
)

Reads observation data from a file and stores it in arrays.

This function reads observation data from a specified file in either ASCII or NetCDF format, depending on the value of the OBS_TYPE control parameter. It stores the time, altitude, longitude, latitude, and observation values in the provided arrays.

Parameters
filenameThe path to the observation data file.
ctlA pointer to a structure containing control parameters.
rtAn array to store the time values of the observations.
rzAn array to store the altitude values of the observations.
rlonAn array to store the longitude values of the observations.
rlatAn array to store the latitude values of the observations.
robsAn array to store the observation values.
nobsA pointer to an integer variable to store the number of observations read.

The function performs the following steps:

  • Logs an informational message indicating the observation data file being read.
  • Reads the observation data from the file based on the OBS_TYPE control parameter:
    • If ctl->obs_type == 0, it reads the data from an ASCII file using the read_obs_asc function.
    • If ctl->obs_type == 1, it reads the data from a NetCDF file using the read_obs_nc function.
    • If ctl->obs_type is neither 0 nor 1, it generates an error message indicating that the OBS_TYPE must be set to 0 or 1.
  • Checks if the time values are in ascending order and generates an error message if not.
  • Logs statistical information about the observation data, including the number of observations, time range, altitude range, longitude range, latitude range, and observation value range.
Note
The function assumes that the observation data file is formatted correctly and that the arrays provided have sufficient memory allocated to store the data.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 12361 of file mptrac.c.

12369 {
12370
12371 /* Write info... */
12372 LOG(1, "Read observation data: %s", filename);
12373
12374 /* Read data... */
12375 if (ctl->obs_type == 0)
12376 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
12377 else if (ctl->obs_type == 1)
12378 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
12379 else
12380 ERRMSG("Set OBS_TYPE to 0 or 1!");
12381
12382 /* Check time... */
12383 for (int i = 1; i < *nobs; i++)
12384 if (rt[i] < rt[i - 1])
12385 ERRMSG("Time must be ascending!");
12386
12387 /* Write info... */
12388 int n = *nobs;
12389 double mini, maxi;
12390 LOG(2, "Number of observations: %d", *nobs);
12391 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
12392 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
12393 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
12394 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
12395 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
12396 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
12397 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
12398 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
12399 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
12400 LOG(2, "Observation range: %g ... %g", mini, maxi);
12401}
void read_obs_asc(const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
Reads observation data from an ASCII file.
Definition: mptrac.c:12405
void read_obs_nc(const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
Reads observation data from a NetCDF file.
Definition: mptrac.c:12433
Here is the call graph for this function:

◆ read_obs_asc()

void read_obs_asc ( const char *  filename,
double *  rt,
double *  rz,
double *  rlon,
double *  rlat,
double *  robs,
int *  nobs 
)

Reads observation data from an ASCII file.

This function reads observation data from a specified ASCII file. It extracts time, altitude, longitude, latitude, and observation values from each line of the file and stores them in the provided arrays.

Parameters
filenameThe path to the ASCII file containing the observation data.
rtAn array to store the time values of the observations.
rzAn array to store the altitude values of the observations.
rlonAn array to store the longitude values of the observations.
rlatAn array to store the latitude values of the observations.
robsAn array to store the observation values.
nobsA pointer to an integer variable to store the number of observations read.

The function performs the following steps:

  • Attempts to open the specified observation data file in read mode.
  • Reads each line of the file and parses it to extract the time, altitude, longitude, latitude, and observation values using the sscanf function.
  • Stores the extracted values in the respective arrays.
  • Checks if the number of observations exceeds the maximum allowed limit (NOBS) and generates an error message if so.
  • Closes the observation data file after reading all data.
Note
The function assumes that the observation data file is properly formatted and that the arrays provided have sufficient memory allocated to store the data.
Author
Lars Hoffmann

Definition at line 12405 of file mptrac.c.

12412 {
12413
12414 /* Open observation data file... */
12415 FILE *in;
12416 if (!(in = fopen(filename, "r")))
12417 ERRMSG("Cannot open file!");
12418
12419 /* Read observations... */
12420 char line[LEN];
12421 while (fgets(line, LEN, in))
12422 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
12423 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
12424 if ((++(*nobs)) >= NOBS)
12425 ERRMSG("Too many observations!");
12426
12427 /* Close observation data file... */
12428 fclose(in);
12429}
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:588

◆ read_obs_nc()

void read_obs_nc ( const char *  filename,
double *  rt,
double *  rz,
double *  rlon,
double *  rlat,
double *  robs,
int *  nobs 
)

Reads observation data from a NetCDF file.

This function reads observation data from a specified NetCDF file. It extracts time, altitude, longitude, latitude, and observation values from the variables in the NetCDF file and stores them in the provided arrays.

Parameters
filenameThe path to the NetCDF file containing the observation data.
rtAn array to store the time values of the observations.
rzAn array to store the altitude values of the observations.
rlonAn array to store the longitude values of the observations.
rlatAn array to store the latitude values of the observations.
robsAn array to store the observation values.
nobsA pointer to an integer variable to store the number of observations read.

The function performs the following steps:

  • Attempts to open the specified NetCDF file in read-only mode using the nc_open function.
  • Queries the dimensions of the 'nobs' variable in the NetCDF file to determine the number of observations using the NC_INQ_DIM macro.
  • Reads the 'time', 'alt', 'lon', 'lat', and 'obs' variables from the NetCDF file using the NC_GET_DOUBLE macro and stores them in the respective arrays.
  • Closes the NetCDF file after reading all data using the nc_close function.
Note
The function assumes that the NetCDF file contains the required variables ('time', 'alt', 'lon', 'lat', 'obs') and that the arrays provided have sufficient memory allocated to store the data.
Author
Lars Hoffmann

Definition at line 12433 of file mptrac.c.

12440 {
12441
12442 int ncid, varid;
12443
12444 /* Open netCDF file... */
12445 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
12446 ERRMSG("Cannot open file!");
12447
12448 /* Read the observations from the NetCDF file... */
12449 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
12450 NC_GET_DOUBLE("time", rt, 1);
12451 NC_GET_DOUBLE("alt", rz, 1);
12452 NC_GET_DOUBLE("lon", rlon, 1);
12453 NC_GET_DOUBLE("lat", rlat, 1);
12454 NC_GET_DOUBLE("obs", robs, 1);
12455
12456 /* Close file... */
12457 NC(nc_close(ncid));
12458}

◆ scan_ctl()

double scan_ctl ( const char *  filename,
int  argc,
char *  argv[],
const char *  varname,
const int  arridx,
const char *  defvalue,
char *  value 
)

Scans a control file or command-line arguments for a specified variable.

This function scans either a control file or command-line arguments for a specified variable name and retrieves its value. It searches for the variable name in the control file or command-line arguments and returns its corresponding value. If the variable is not found, it returns a default value specified by the user.

Parameters
filenameThe name of the control file to be scanned. If NULL, only command-line arguments will be scanned.
argcThe number of command-line arguments.
argvAn array of command-line arguments.
varnameThe name of the variable to be searched.
arridxThe index of the variable array, if applicable. Set to -1 if not an array.
defvalueThe default value to be returned if the variable is not found.
valueA pointer to a character array to store the retrieved value.
Returns
The retrieved value of the variable as a double.

The function performs the following steps:

  • Attempts to open the specified control file in read mode using the fopen function. If the filename ends with a '-', the file is not opened.
  • Constructs the full variable name based on the variable name and array index provided.
  • Reads data from the control file, searching for the full variable name. If found, it sets the contain flag to 1 and breaks the loop.
  • Searches through the command-line arguments for the full variable name. If found, it sets the value and contain flag and breaks the loop.
  • Closes the control file if opened.
  • If the variable is not found, it sets the value to the default value provided or throws an error if no default value is provided.
  • Writes the variable name and its value to the log.
  • Copies the retrieved value to the value parameter if it is not NULL.
  • Returns the retrieved value as a double after converting it from a string using the atof function.
Note
This function assumes that the variable names and their values in the control file or command-line arguments are separated by whitespace.
Author
Lars Hoffmann

Definition at line 12462 of file mptrac.c.

12469 {
12470
12471 FILE *in = NULL;
12472
12473 char fullname1[LEN], fullname2[LEN], rval[LEN];
12474
12475 int contain = 0, i;
12476
12477 /* Open file... */
12478 if (filename[strlen(filename) - 1] != '-')
12479 if (!(in = fopen(filename, "r")))
12480 ERRMSG("Cannot open file!");
12481
12482 /* Set full variable name... */
12483 if (arridx >= 0) {
12484 sprintf(fullname1, "%s[%d]", varname, arridx);
12485 sprintf(fullname2, "%s[*]", varname);
12486 } else {
12487 sprintf(fullname1, "%s", varname);
12488 sprintf(fullname2, "%s", varname);
12489 }
12490
12491 /* Read data... */
12492 if (in != NULL) {
12493 char dummy[LEN], line[LEN], rvarname[LEN];
12494 while (fgets(line, LEN, in)) {
12495 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
12496 if (strcasecmp(rvarname, fullname1) == 0 ||
12497 strcasecmp(rvarname, fullname2) == 0) {
12498 contain = 1;
12499 break;
12500 }
12501 }
12502 }
12503 for (i = 1; i < argc - 1; i++)
12504 if (strcasecmp(argv[i], fullname1) == 0 ||
12505 strcasecmp(argv[i], fullname2) == 0) {
12506 sprintf(rval, "%s", argv[i + 1]);
12507 contain = 1;
12508 break;
12509 }
12510
12511 /* Close file... */
12512 if (in != NULL)
12513 fclose(in);
12514
12515 /* Check for missing variables... */
12516 if (!contain) {
12517 if (strlen(defvalue) > 0)
12518 sprintf(rval, "%s", defvalue);
12519 else
12520 ERRMSG("Missing variable %s!\n", fullname1);
12521 }
12522
12523 /* Write info... */
12524 LOG(1, "%s = %s", fullname1, rval);
12525
12526 /* Return values... */
12527 if (value != NULL)
12528 sprintf(value, "%s", rval);
12529 return atof(rval);
12530}

◆ sedi()

double sedi ( const double  p,
const double  T,
const double  rp,
const double  rhop 
)

Calculates the sedimentation velocity of a particle in air.

This function calculates the sedimentation velocity of a particle in air using the given parameters.

Parameters
pThe atmospheric pressure [hPa].
TThe temperature [K].
rpThe radius of the particle [microns].
rhopThe density of the particle [kg/m^3].
Returns
The sedimentation velocity of the particle [m/s].

The function performs the following steps:

  • Converts the radius of the particle from microns to meters.
  • Calculates the density of dry air using the given atmospheric pressure and temperature.
  • Calculates the dynamic viscosity of air using Sutherland's formula.
  • Calculates the thermal velocity of an air molecule using the given temperature.
  • Calculates the mean free path of an air molecule.
  • Computes the Knudsen number for air based on the ratio of mean free path to particle radius.
  • Applies the Cunningham slip-flow correction factor to account for particle size.
  • Computes the sedimentation velocity of the particle based on the difference in densities between the particle and air, incorporating the slip-flow correction.
Note
This function assumes that the ideal gas law and Stokes' law are applicable for calculating the sedimentation velocity of the particle.
Author
Lars Hoffmann

Definition at line 12534 of file mptrac.c.

12538 {
12539
12540 /* Convert particle radius from microns to m... */
12541 const double rp_help = rp * 1e-6;
12542
12543 /* Density of dry air [kg / m^3]... */
12544 const double rho = RHO(p, T);
12545
12546 /* Dynamic viscosity of air [kg / (m s)]... */
12547 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
12548
12549 /* Thermal velocity of an air molecule [m / s]... */
12550 const double v = sqrt(8. * KB * T / (M_PI * M_AIR_MOLECULE));
12551
12552 /* Mean free path of an air molecule [m]... */
12553 const double lambda = 2. * eta / (rho * v);
12554
12555 /* Knudsen number for air (dimensionless)... */
12556 const double K = lambda / rp_help;
12557
12558 /* Cunningham slip-flow correction (dimensionless)... */
12559 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
12560
12561 /* Sedimentation velocity [m / s]... */
12562 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
12563}
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:284
#define M_AIR_MOLECULE
Mean mass of an air molecule [kg].
Definition: mptrac.h:339

◆ spline()

void spline ( const double *  x,
const double *  y,
const int  n,
const double *  x2,
double *  y2,
const int  n2,
const int  method 
)

Performs spline interpolation or linear interpolation.

This function interpolates a set of data points using either cubic spline interpolation or linear interpolation, depending on the specified method.

Parameters
xThe array of x-coordinates of the data points.
yThe array of y-coordinates of the data points.
nThe number of data points.
x2The array of x-coordinates where interpolation is required.
y2The array to store the interpolated y-values.
n2The number of points to interpolate.
methodThe interpolation method: 1 for cubic spline, 0 for linear interpolation.

If the method is set to 1 (cubic spline interpolation):

  • The function initializes a cubic spline interpolator using GSL.
  • It interpolates the y-values at the specified x-coordinates using the spline.
  • The interpolated y-values are stored in the provided y2 array.

If the method is set to 0 (linear interpolation):

  • The function performs linear interpolation between adjacent data points.
  • It locates the interval where each interpolation point falls and calculates the interpolated y-value using linear interpolation.
  • The interpolated y-values are stored in the provided y2 array.
Note
The x-coordinates in both arrays (x and x2) must be sorted in ascending order.
Author
Lars Hoffmann

Definition at line 12567 of file mptrac.c.

12574 {
12575
12576 /* Cubic spline interpolation... */
12577 if (method == 1) {
12578
12579 /* Allocate... */
12580 gsl_interp_accel *acc = gsl_interp_accel_alloc();
12581 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
12582
12583 /* Interpolate profile... */
12584 gsl_spline_init(s, x, y, (size_t) n);
12585 for (int i = 0; i < n2; i++)
12586 if (x2[i] <= x[0])
12587 y2[i] = y[0];
12588 else if (x2[i] >= x[n - 1])
12589 y2[i] = y[n - 1];
12590 else
12591 y2[i] = gsl_spline_eval(s, x2[i], acc);
12592
12593 /* Free... */
12594 gsl_spline_free(s);
12595 gsl_interp_accel_free(acc);
12596 }
12597
12598 /* Linear interpolation... */
12599 else {
12600 for (int i = 0; i < n2; i++)
12601 if (x2[i] <= x[0])
12602 y2[i] = y[0];
12603 else if (x2[i] >= x[n - 1])
12604 y2[i] = y[n - 1];
12605 else {
12606 const int idx = locate_irr(x, n, x2[i]);
12607 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
12608 }
12609 }
12610}
Here is the call graph for this function:

◆ stddev()

float stddev ( const float *  data,
const int  n 
)

Calculates the standard deviation of a set of data.

This function calculates the standard deviation of a set of floating-point data values.

Parameters
dataPointer to the array of data values.
nNumber of data values in the array.
Returns
The standard deviation of the data values. If the number of data values is less than or equal to 0, returns 0.

The standard deviation is calculated using the formula:

\[ \sigma = \sqrt{\frac{\sum_{i=1}^{n} (x_i - \bar{x})^2}{n}} \]

where:

  • \( \sigma \) is the standard deviation,
  • \( x_i \) is each data value,
  • \( \bar{x} \) is the mean of the data values, and
  • \( n \) is the total number of data values.
Author
Lars Hoffmann

Definition at line 12614 of file mptrac.c.

12616 {
12617
12618 if (n <= 0)
12619 return 0;
12620
12621 float mean = 0, var = 0;
12622
12623 for (int i = 0; i < n; ++i) {
12624 mean += data[i];
12625 var += SQR(data[i]);
12626 }
12627
12628 var = var / (float) n - SQR(mean / (float) n);
12629
12630 return (var > 0 ? sqrtf(var) : 0);
12631}

◆ time2jsec()

void time2jsec ( const int  year,
const int  mon,
const int  day,
const int  hour,
const int  min,
const int  sec,
const double  remain,
double *  jsec 
)

Converts time components to seconds since January 1, 2000, 12:00:00 UTC.

This function calculates the number of seconds elapsed since January 1, 2000, 12:00:00 UTC, based on the provided year, month, day, hour, minute, and second. It also includes a fractional part to represent the remaining seconds.

Parameters
yearThe year.
monThe month (1-12).
dayThe day of the month (1-31).
hourThe hour of the day (0-23).
minThe minute (0-59).
secThe second (0-59).
remainThe fractional part of seconds.
jsecPointer to store the calculated number of seconds since January 1, 2000, 12:00:00 UTC.

The function calculates the time elapsed since January 1, 2000, 12:00:00 UTC, up to the specified time and includes any fractional seconds indicated by the "remain" parameter.

Note
The function uses the timegm function, which is similar to mktime but operates in UTC.
Author
Lars Hoffmann

Definition at line 12635 of file mptrac.c.

12643 {
12644
12645 struct tm t0, t1;
12646
12647 t0.tm_year = 100;
12648 t0.tm_mon = 0;
12649 t0.tm_mday = 1;
12650 t0.tm_hour = 0;
12651 t0.tm_min = 0;
12652 t0.tm_sec = 0;
12653
12654 t1.tm_year = year - 1900;
12655 t1.tm_mon = mon - 1;
12656 t1.tm_mday = day;
12657 t1.tm_hour = hour;
12658 t1.tm_min = min;
12659 t1.tm_sec = sec;
12660
12661 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
12662}

◆ timer()

void timer ( const char *  name,
const char *  group,
const int  output 
)

Measures and reports elapsed time for named and grouped timers.

The timer function measures elapsed time for a specified named timer and an optional group of timers, accumulating time statistics such as minimum, maximum, and mean elapsed times. It also provides an option to log the timing statistics to an output.

Parameters
nameA string representing the name of the timer.
groupA string representing the group to which the timer belongs.
outputAn integer flag indicating whether to report the timing statistics (non-zero to report).

The function keeps track of multiple timers and groups. When called, it:

  • Gets the current time and calculates the elapsed time since the last call.
  • Adds the elapsed time to the current timers' statistics.
  • Reports the statistics if the output parameter is non-zero.
  • Identifies the IDs of the next timer and group based on the provided name and group.
  • Checks if the name and group are new, and if so, initializes them.
  • Saves the starting time for the next measurement.
Note
The function uses OpenMP's omp_get_wtime() to get the current wall time.
The function maintains static arrays and variables to store timer names, groups, and statistics.
The maximum number of timers and groups is defined by the NTIMER macro.
Warning
If the number of timers or groups exceeds NTIMER, the function will trigger an error message.
Author
Lars Hoffmann

Definition at line 12666 of file mptrac.c.

12669 {
12670
12671 static char names[NTIMER][100], groups[NTIMER][100];
12672
12673 static double rt_name[NTIMER], rt_group[NTIMER],
12674 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
12675
12676 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
12677
12678 /* Get time... */
12679 t1 = omp_get_wtime();
12680 dt = t1 - t0;
12681
12682 /* Add elapsed time to current timers... */
12683 if (iname >= 0) {
12684 rt_name[iname] += dt;
12685 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
12686 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
12687 ct_name[iname]++;
12688 }
12689 if (igroup >= 0)
12690 rt_group[igroup] += t1 - t0;
12691
12692 /* Report timers... */
12693 if (output) {
12694 for (int i = 0; i < nname; i++)
12695 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
12696 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
12697 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
12698 for (int i = 0; i < ngroup; i++)
12699 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
12700 double total = 0.0;
12701 for (int i = 0; i < nname; i++)
12702 total += rt_name[i];
12703 LOG(1, "TIMER_TOTAL = %.3f s", total);
12704 }
12705
12706 /* Identify IDs of next timer... */
12707 for (iname = 0; iname < nname; iname++)
12708 if (strcasecmp(name, names[iname]) == 0)
12709 break;
12710 for (igroup = 0; igroup < ngroup; igroup++)
12711 if (strcasecmp(group, groups[igroup]) == 0)
12712 break;
12713
12714 /* Check whether this is a new timer... */
12715 if (iname >= nname) {
12716 sprintf(names[iname], "%s", name);
12717 if ((++nname) >= NTIMER)
12718 ERRMSG("Too many timers!");
12719 }
12720
12721 /* Check whether this is a new group... */
12722 if (igroup >= ngroup) {
12723 sprintf(groups[igroup], "%s", group);
12724 if ((++ngroup) >= NTIMER)
12725 ERRMSG("Too many groups!");
12726 }
12727
12728 /* Save starting time... */
12729 t0 = t1;
12730}
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2449

◆ time_from_filename()

double time_from_filename ( const char *  filename,
const int  offset,
const int  with_seconds 
)

Extracts and converts a timestamp from a filename to Julian seconds.

The time_from_filename function parses a given filename to extract a timestamp and converts it to Julian seconds. The timestamp is expected to follow a specific format and position within the filename, defined by the offset parameter.

Parameters
filenameA string representing the filename containing the timestamp.
offsetAn integer indicating the position from the end of the filename where the timestamp starts.
with_secondsAn integer indicating if the filename contains seconds or not.
Returns
The time in Julian seconds as a double.

The function performs the following steps:

  • Extracts the year, month, day, hour, minute and (optionally) second components of the timestamp from the filename using the given offset.
  • Validates the extracted components to ensure they represent a valid date and time.
  • Converts the validated date and time components to Julian seconds using the time2jsec function.
  • Returns the computed time in Julian seconds.
Note
The expected formats of the timestamp in the filename are:
  • if with_seconds=0: YYYY-MM-DD_HH-MM (e.g., "2023-05-27_14-45")
  • if with_seconds=1: YYYY-MM-DD_HH-MM-SS (e.g., "2023-05-27_14-45-12")
Warning
If the extracted components do not represent a valid date and time, the function will trigger an error message.
Author
Lars Hoffmann

Definition at line 12734 of file mptrac.c.

12737 {
12738
12739 char tstr[10];
12740
12741 double t;
12742
12743 /* Get time from filename... */
12744 int len = (int) strlen(filename);
12745 sprintf(tstr, "%.4s", &filename[len - offset]);
12746 int year = atoi(tstr);
12747 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
12748 int mon = atoi(tstr);
12749 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
12750 int day = atoi(tstr);
12751 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
12752 int hour = atoi(tstr);
12753 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
12754 int min = atoi(tstr);
12755
12756 int sec = 0;
12757 if (with_seconds) {
12758 sprintf(tstr, "%.2s", &filename[len - offset + 17]);
12759 sec = atoi(tstr);
12760 }
12761
12762 /* Check time... */
12763 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
12764 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
12765 ERRMSG("Cannot read time from filename!");
12766
12767 /* Convert time to Julian seconds... */
12768 time2jsec(year, mon, day, hour, min, sec, 0.0, &t);
12769
12770 /* Return time... */
12771 return t;
12772}
Here is the call graph for this function:

◆ tropo_weight()

double tropo_weight ( const ctl_t ctl,
const clim_t clim,
const atm_t atm,
const int  ip 
)

Computes a weighting factor based on tropopause pressure.

This function calculates a weighting factor for a given pressure value in relation to the tropopause pressure. The weighting factor is determined as follows:

  • Returns 1 if the pressure is greater than a calculated upper limit.
  • Returns 0 if the pressure is less than a calculated lower limit.
  • Linearly interpolates between 1 and 0 within the range defined by the upper and lower limits.
Parameters
[in]ctlPointer to the control data structure.
[in]climPointer to the climatology data structure.
[in]atmPointer to the atmospheric data structure.
[in]ipIndex of the pressure value to evaluate within the atmospheric data.
Returns
Weighting factor (double) in the range [0, 1].
Author
Lars Hoffmann

Definition at line 12776 of file mptrac.c.

12780 {
12781
12782 /* Get tropopause pressure... */
12783 const double pt = clim_tropo(clim, atm->time[ip],
12784 ctl->met_coord_type ==
12785 0 ? atm->lat[ip] : ctl->met_utm_ref_lat);
12786
12787 /* Get pressure range... */
12788 const double p1 = pt * 0.866877899;
12789 const double p0 = pt / 0.866877899;
12790
12791 /* Get weighting factor... */
12792 if (atm->p[ip] > p0)
12793 return 1;
12794 else if (atm->p[ip] < p1)
12795 return 0;
12796 else
12797 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
12798}
Here is the call graph for this function:

◆ write_atm_asc()

void write_atm_asc ( const char *  filename,
const ctl_t ctl,
const atm_t atm,
const double  t 
)

Writes air parcel data to an ASCII file or gnuplot.

The write_atm_asc function writes the atmospheric data stored in the atm structure to an ASCII file specified by filename or to pipe to gnuplot if requested.

Parameters
filenameA string representing the name of the file to write the data to.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.
tThe current time used for filtering and timestamping.

The function performs the following steps:

  • Sets the time interval for the output data based on the control parameters.
  • Checks if gnuplot output is requested and, if so, creates a pipe to gnuplot and sets up the plot.
  • If gnuplot output is not requested, creates an ASCII file for writing.
  • Writes the header information to the output file, including the description of each column.
  • Iterates over the particles in the atm structure, filtering by time if specified, and writes the data to the output file.
  • Closes the output file or gnuplot pipe.
Author
Lars Hoffmann

Definition at line 12802 of file mptrac.c.

12806 {
12807
12808 FILE *out;
12809
12810 /* Set time interval for output... */
12811 const double t0 = t - 0.5 * ctl->dt_mod;
12812 const double t1 = t + 0.5 * ctl->dt_mod;
12813
12814 /* Check if gnuplot output is requested... */
12815 if (ctl->atm_gpfile[0] != '-') {
12816
12817 /* Create gnuplot pipe... */
12818 if (!(out = popen("gnuplot", "w")))
12819 ERRMSG("Cannot create pipe to gnuplot!");
12820
12821 /* Set plot filename... */
12822 fprintf(out, "set out \"%s.png\"\n", filename);
12823
12824 /* Set time string... */
12825 double r;
12826 int year, mon, day, hour, min, sec;
12827 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12828 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12829 year, mon, day, hour, min);
12830
12831 /* Dump gnuplot file to pipe... */
12832 FILE *in;
12833 if (!(in = fopen(ctl->atm_gpfile, "r")))
12834 ERRMSG("Cannot open file!");
12835 char line[LEN];
12836 while (fgets(line, LEN, in))
12837 fprintf(out, "%s", line);
12838 fclose(in);
12839 }
12840
12841 else {
12842
12843 /* Create file... */
12844 if (!(out = fopen(filename, "w")))
12845 ERRMSG("Cannot create file!");
12846 }
12847
12848 /* Write header... */
12849
12850 if (ctl->met_coord_type == 0) {
12851 fprintf(out,
12852 "# $1 = time [s]\n"
12853 "# $2 = altitude [km]\n"
12854 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12855 } else {
12856 fprintf(out,
12857 "# $1 = time [s]\n"
12858 "# $2 = altitude [km]\n" "# $3 = x [m]\n" "# $4 = y [m]\n");
12859 }
12860
12861 for (int iq = 0; iq < ctl->nq; iq++)
12862 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
12863 ctl->qnt_unit[iq]);
12864 fprintf(out, "\n");
12865
12866 /* Write data... */
12867 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
12868
12869 /* Check time... */
12870 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12871 continue;
12872
12873 /* Write output... */
12874 if (ctl->met_coord_type == 0) {
12875 fprintf(out, "%.2f %g %g %g",
12876 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]
12877 );
12878 } else {
12879 fprintf(out, "%.2f %g %.2f %.2f",
12880 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]
12881 );
12882 }
12883
12884 for (int iq = 0; iq < ctl->nq; iq++) {
12885 fprintf(out, " ");
12886 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12887 fprintf(out, ctl->qnt_format[iq], NAN);
12888 else
12889 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
12890 }
12891 fprintf(out, "\n");
12892 }
12893
12894 /* Close file... */
12895 fclose(out);
12896}
Here is the call graph for this function:

◆ write_atm_bin()

void write_atm_bin ( const char *  filename,
const ctl_t ctl,
const atm_t atm 
)

Writes air parcel data to a binary file.

The write_atm_bin function writes the air parcel data stored in the atm structure to a binary file specified by filename. The function includes versioning information and ensures that all relevant data arrays are written in a consistent binary format.

Parameters
filenameA string representing the name of the file to write the data to.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.

The function performs the following steps:

  • Creates the binary file for writing. If the file cannot be created, it triggers an error message.
  • Writes a version number for the binary data format.
  • Writes the number of particles to the file.
  • Writes the time, pressure, longitude, and latitude arrays to the file.
  • Iterates over the quantities specified in the ctl structure and writes each quantity array to the file.
  • Writes a final flag to indicate the end of the binary data.
  • Closes the file.
Author
Lars Hoffmann

Definition at line 12900 of file mptrac.c.

12903 {
12904
12905 FILE *out;
12906
12907 /* Create file... */
12908 if (!(out = fopen(filename, "w")))
12909 ERRMSG("Cannot create file!");
12910
12911 /* Write version of binary data... */
12912 int version = 100;
12913 FWRITE(&version, int,
12914 1,
12915 out);
12916
12917 /* Write data... */
12918 FWRITE(&atm->np, int,
12919 1,
12920 out);
12921 FWRITE(atm->time, double,
12922 (size_t) atm->np,
12923 out);
12924 FWRITE(atm->p, double,
12925 (size_t) atm->np,
12926 out);
12927 FWRITE(atm->lon, double,
12928 (size_t) atm->np,
12929 out);
12930 FWRITE(atm->lat, double,
12931 (size_t) atm->np,
12932 out);
12933 for (int iq = 0; iq < ctl->nq; iq++)
12934 FWRITE(atm->q[iq], double,
12935 (size_t) atm->np,
12936 out);
12937
12938 /* Write final flag... */
12939 int final = 999;
12940 FWRITE(&final, int,
12941 1,
12942 out);
12943
12944 /* Close file... */
12945 fclose(out);
12946}

◆ write_atm_clams()

void write_atm_clams ( const char *  filename,
const ctl_t ctl,
const atm_t atm 
)

Writes air parcel data to a NetCDF file in the CLaMS format.

The write_atm_clams function creates a NetCDF file and writes air parcel data into it. The data includes time, latitude, longitude, pressure, and other specified quantities. The function defines the dimensions and variables, sets global attributes, and writes the data to the file.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.

The function performs the following steps:

  • Creates the NetCDF file with the specified filename.
  • Defines the dimensions for time and the number of particles (NPARTS).
  • Defines variables for time, latitude, longitude, pressure, zeta, and other quantities.
  • Sets global attributes for the vertical coordinate name and model.
  • Writes the data into the NetCDF file.
  • Closes the NetCDF file after writing.
Author
Jan Clemens

Definition at line 12950 of file mptrac.c.

12953 {
12954
12955 if (ctl->met_coord_type != 0)
12956 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
12957
12958 int tid, pid, ncid, varid;
12959 size_t start[2], count[2];
12960
12961 /* Create file... */
12962 NC(nc_create(filename, NC_NETCDF4, &ncid));
12963
12964 /* Define dimensions... */
12965 NC(nc_def_dim(ncid, "time", 1, &tid));
12966 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12967
12968 /* Define variables and their attributes... */
12969 int dim_ids[2] = { tid, pid };
12970 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12971 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12972 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
12973 ctl->atm_nc_level, 0);
12974 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
12975 ctl->atm_nc_level, 0);
12976 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
12977 ctl->atm_nc_level, 0);
12978 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
12979 for (int iq = 0; iq < ctl->nq; iq++)
12980 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12981 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12982 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12983
12984 /* Define global attributes... */
12985 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12986 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12987
12988 /* End definitions... */
12989 NC(nc_enddef(ncid));
12990
12991 /* Write data... */
12992 NC_PUT_DOUBLE("time", atm->time, 0);
12993 NC_PUT_DOUBLE("LAT", atm->lat, 0);
12994 NC_PUT_DOUBLE("LON", atm->lon, 0);
12995 NC_PUT_DOUBLE("PRESS", atm->p, 0);
12996 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
12997 for (int iq = 0; iq < ctl->nq; iq++)
12998 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12999
13000 /* Close file... */
13001 NC(nc_close(ncid));
13002}
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1706
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1536
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1620

◆ write_atm_clams_traj()

void write_atm_clams_traj ( const char *  dirname,
const ctl_t ctl,
const atm_t atm,
const double  t 
)

Writes CLaMS trajectory data to a NetCDF file.

The write_atm_clams_traj function writes trajectory data for the CLaMS model to a NetCDF file. The file is created and populated with data including time, latitude, longitude, pressure, and other quantities. The function also handles the creation of a final initialization file at the last time step.

Parameters
dirnameA string representing the directory name where the file will be created.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.
tThe current time in seconds since a reference epoch.

The function performs the following steps:

  • Determines the start and stop times of the calculation.
  • Constructs the output filename based on the start and stop times.
  • Defines the hyperslab for the trajectory file.
  • Creates the NetCDF file if it's the first time step and defines dimensions and variables.
  • Writes the trajectory data to the NetCDF file.
  • At the last time step, creates an initialization file with the final data.
Author
Jan Clemens

Definition at line 13006 of file mptrac.c.

13010 {
13011
13012 if (ctl->met_coord_type != 0)
13013 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
13014
13015 /* Global Counter... */
13016 static size_t out_cnt = 0;
13017
13018 double r, r_start, r_stop;
13019 int year, mon, day, hour, min, sec;
13020 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
13021 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
13022 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
13023
13024 int ncid, varid, tid, pid, cid;
13025 int dim_ids[2];
13026
13027 /* time, nparc */
13028 size_t start[2];
13029 size_t count[2];
13030
13031 /* Determine start and stop times of calculation... */
13032 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
13033 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
13034 &min_start, &sec_start, &r_start);
13035 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
13036 &min_stop, &sec_stop, &r_stop);
13037
13038 sprintf(filename_out,
13039 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
13040 year_start % 100, mon_start, day_start, hour_start,
13041 year_stop % 100, mon_stop, day_stop, hour_stop);
13042 LOG(1, "Write traj file: %s", filename_out);
13043
13044 /* Define hyperslap for the traj_file... */
13045 start[0] = out_cnt;
13046 start[1] = 0;
13047 count[0] = 1;
13048 count[1] = (size_t) atm->np;
13049
13050 /* Create the file at the first timestep... */
13051 if (out_cnt == 0) {
13052
13053 /* Create file... */
13054 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
13055
13056 /* Define dimensions... */
13057 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
13058 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
13059 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
13060 dim_ids[0] = tid;
13061 dim_ids[1] = pid;
13062
13063 /* Define variables and their attributes... */
13064 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
13065 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
13066 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
13067 ctl->atm_nc_level, 0);
13068 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
13069 ctl->atm_nc_level, 0);
13070 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
13071 ctl->atm_nc_level, 0);
13072 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
13073 ctl->atm_nc_level, 0);
13074 for (int iq = 0; iq < ctl->nq; iq++)
13075 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
13076 ctl->qnt_name[iq], ctl->qnt_unit[iq],
13077 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
13078
13079 /* Define global attributes... */
13080 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
13081 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
13082
13083 /* End definitions... */
13084 NC(nc_enddef(ncid));
13085 NC(nc_close(ncid));
13086 }
13087
13088 /* Increment global counter to change hyperslap... */
13089 out_cnt++;
13090
13091 /* Open file... */
13092 NC(nc_open(filename_out, NC_WRITE, &ncid));
13093
13094 /* Write data... */
13095 NC_PUT_DOUBLE("time", atm->time, 1);
13096 NC_PUT_DOUBLE("LAT", atm->lat, 1);
13097 NC_PUT_DOUBLE("LON", atm->lon, 1);
13098 NC_PUT_DOUBLE("PRESS", atm->p, 1);
13099 if (ctl->advect_vert_coord == 1) {
13100 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
13101 } else if (ctl->qnt_zeta >= 0) {
13102 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
13103 }
13104 for (int iq = 0; iq < ctl->nq; iq++)
13105 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
13106
13107 /* Close file... */
13108 NC(nc_close(ncid));
13109
13110 /* At the last time step create the init_fix_YYYYMMDDHH file... */
13111 if ((year == year_stop) && (mon == mon_stop)
13112 && (day == day_stop) && (hour == hour_stop)) {
13113
13114 /* Set filename... */
13115 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
13116 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
13117 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
13118 LOG(1, "Write init file: %s", filename_init);
13119
13120 /* Create file... */
13121 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
13122
13123 /* Define dimensions... */
13124 NC(nc_def_dim(ncid, "time", 1, &tid));
13125 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
13126 dim_ids[0] = tid;
13127 dim_ids[1] = pid;
13128
13129 /* Define variables and their attributes... */
13130 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
13131 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
13132 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
13133 ctl->atm_nc_level, 0);
13134 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
13135 ctl->atm_nc_level, 0);
13136 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
13137 ctl->atm_nc_level, 0);
13138 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
13139 for (int iq = 0; iq < ctl->nq; iq++)
13140 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
13141 ctl->qnt_name[iq], ctl->qnt_unit[iq],
13142 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
13143
13144 /* Define global attributes... */
13145 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
13146 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
13147
13148 /* End definitions... */
13149 NC(nc_enddef(ncid));
13150
13151 /* Write data... */
13152 NC_PUT_DOUBLE("time", atm->time, 0);
13153 NC_PUT_DOUBLE("LAT", atm->lat, 0);
13154 NC_PUT_DOUBLE("LON", atm->lon, 0);
13155 NC_PUT_DOUBLE("PRESS", atm->p, 0);
13156 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
13157 for (int iq = 0; iq < ctl->nq; iq++)
13158 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
13159
13160 /* Close file... */
13161 NC(nc_close(ncid));
13162 }
13163}
Here is the call graph for this function:

◆ write_atm_nc()

void write_atm_nc ( const char *  filename,
const ctl_t ctl,
const atm_t atm 
)

Writes air parcel data to a NetCDF file.

The write_atm_nc function creates a NetCDF file and writes air parcel data into it. The data includes time, pressure, longitude, latitude, and other specified quantities. The function defines the dimensions and variables, sets global attributes, and writes the data to the file.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.

The function performs the following steps:

  • Creates the NetCDF file with the specified filename.
  • Defines the dimension for the number of observations (obs).
  • Defines variables for time, pressure, longitude, latitude, and other quantities.
  • Sets global attributes for the feature type.
  • Writes the data into the NetCDF file.
  • Closes the NetCDF file after writing.
Author
Lars Hoffmann

Definition at line 13167 of file mptrac.c.

13170 {
13171
13172 int ncid, obsid, varid;
13173
13174 size_t start[2], count[2];
13175
13176 /* Create file... */
13177 NC(nc_create(filename, NC_NETCDF4, &ncid));
13178
13179 /* Define dimensions... */
13180 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
13181
13182 /* Define variables and their attributes... */
13183 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
13184 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
13185 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
13186 ctl->atm_nc_level, 0);
13187 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
13188 ctl->atm_nc_level, 0);
13189 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
13190 ctl->atm_nc_level, 0);
13191 for (int iq = 0; iq < ctl->nq; iq++)
13192 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
13193 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
13194 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
13195
13196 /* Define global attributes... */
13197 NC_PUT_ATT_GLOBAL("featureType", "point");
13198
13199 /* End definitions... */
13200 NC(nc_enddef(ncid));
13201
13202 /* Write data... */
13203 NC_PUT_DOUBLE("time", atm->time, 0);
13204 NC_PUT_DOUBLE("press", atm->p, 0);
13205 NC_PUT_DOUBLE("lon", atm->lon, 0);
13206 NC_PUT_DOUBLE("lat", atm->lat, 0);
13207 for (int iq = 0; iq < ctl->nq; iq++)
13208 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
13209
13210 /* Close file... */
13211 NC(nc_close(ncid));
13212}

◆ write_csi()

void write_csi ( const char *  filename,
const ctl_t ctl,
const atm_t atm,
const double  t 
)

Writes Critical Success Index (CSI) data to a file.

The write_csi function processes air parcel and observation data to calculate and write various verification statistics, including the Critical Success Index (CSI), to a specified output file at regular intervals. The statistics include measures such as the number of hits, misses, and false alarms, bias, probability of detection, false alarm rate, equitable threat score, and correlation coefficients.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.
tA double representing the current time.

The function performs the following steps:

  • Initializes resources and sets up the output file if the current time is the start time.
  • Reads observation data and kernel data if provided.
  • Sets grid box sizes and horizontal coordinates.
  • Allocates memory for mean and count arrays.
  • Loops over observations and model data to accumulate mean values and counts.
  • Analyzes the grid cells to calculate CSI and other statistics.
  • Writes the calculated statistics to the output file at specified intervals.
  • Frees allocated resources and closes the file when the processing is complete.
Author
Lars Hoffmann

Definition at line 13216 of file mptrac.c.

13220 {
13221
13222 if (ctl->met_coord_type != 0)
13223 ERRMSG("Only lat/lon grid supported");
13224
13225 static FILE *out;
13226
13227 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
13228 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
13229
13230 static int *obscount, nobs, nk;
13231
13232 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
13233
13234 const int ensemble = (ctl->nens > 0);
13235
13236 /* Set timer */
13237 SELECT_TIMER("WRITE_CSI", "OUTPUT");
13238
13239 /* Check quantities... */
13240 if (ctl->qnt_m < 0)
13241 ERRMSG("Need quantity mass!");
13242 if (ensemble) {
13243 if (ctl->qnt_ens < 0)
13244 ERRMSG("Missing ensemble IDs!");
13245 if (ctl->nens > NENS)
13246 ERRMSG("Too many ensembles!");
13247 }
13248
13249 /* Init... */
13250 if (t == ctl->t_start) {
13251
13252 /* Allocate.. */
13253 ALLOC(area, double,
13254 ctl->csi_ny);
13255 ALLOC(rt, double,
13256 NOBS);
13257 ALLOC(rz, double,
13258 NOBS);
13259 ALLOC(rlon, double,
13260 NOBS);
13261 ALLOC(rlat, double,
13262 NOBS);
13263 ALLOC(robs, double,
13264 NOBS);
13265
13266 /* Read observation data... */
13267 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13268
13269 /* Read kernel data... */
13270 if (ctl->csi_kernel[0] != '-')
13271 read_kernel(ctl->csi_kernel, kz, kw, &nk);
13272
13273 /* Create new file... */
13274 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
13275 if (!(out = fopen(filename, "w")))
13276 ERRMSG("Cannot create file!");
13277
13278 /* Write header... */
13279 fprintf(out,
13280 "# $1 = time [s]\n"
13281 "# $2 = ensemble ID\n"
13282 "# $3 = number of hits (cx)\n"
13283 "# $4 = number of misses (cy)\n"
13284 "# $5 = number of false alarms (cz)\n"
13285 "# $6 = number of observations (cx + cy)\n"
13286 "# $7 = number of forecasts (cx + cz)\n"
13287 "# $8 = bias (%%)\n"
13288 "# $9 = POD (%%)\n"
13289 "# $10 = FAR (%%)\n"
13290 "# $11 = CSI (%%)\n"
13291 "# $12 = hits by random chance\n"
13292 "# $13 = ETS (%%)\n"
13293 "# $14 = Pearson R\n"
13294 "# $15 = Spearman R\n"
13295 "# $16 = mean error [kg/m²]\n"
13296 "# $17 = RMSE [kg/m²]\n"
13297 "# $18 = MAE [kg/m²]\n"
13298 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
13299
13300 /* Set grid box size... */
13301 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
13302 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
13303 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
13304
13305 /* Set horizontal coordinates... */
13306 for (int iy = 0; iy < ctl->csi_ny; iy++) {
13307 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
13308 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
13309 }
13310 }
13311
13312 /* Set time interval... */
13313 const double t0 = t - 0.5 * ctl->dt_mod;
13314 const double t1 = t + 0.5 * ctl->dt_mod;
13315
13316 /* Allocate... */
13317 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
13318 ALLOC(modmean, double,
13319 (ensemble ? ctl->nens : 1) * grid_size);
13320 ALLOC(obsmean, double,
13321 grid_size);
13322 ALLOC(obscount, int,
13323 grid_size);
13324 ALLOC(obsstd, double,
13325 grid_size);
13326
13327 /* Init... */
13328 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
13329 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
13330
13331 /* Loop over observations... */
13332 for (int i = 0; i < nobs; i++) {
13333 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
13334 continue;
13335
13336 /* Check grid boundaries and calculate indices... */
13337 if (rlon[i] < ctl->csi_lon0 || rlon[i] >= ctl->csi_lon1
13338 || rlat[i] < ctl->csi_lat0 || rlat[i] >= ctl->csi_lat1
13339 || rz[i] < ctl->csi_z0 || rz[i] >= ctl->csi_z1)
13340 continue;
13341 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
13342 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
13343 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
13344 if (ix >= ctl->csi_nx || iy >= ctl->csi_ny || iz >= ctl->csi_nz)
13345 continue;
13346
13347 /* Get mean observation index... */
13348 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13349 obsmean[idx] += robs[i];
13350 obsstd[idx] += SQR(robs[i]);
13351 obscount[idx]++;
13352 }
13353
13354 /* Analyze model data... */
13355 for (int ip = 0; ip < atm->np; ip++) {
13356
13357 /* Check time... */
13358 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13359 continue;
13360
13361 /* Get ensemble ID... */
13362 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
13363 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
13364 ERRMSG("Ensemble ID out of range!");
13365
13366 /* Check grid boundaries and get indices... */
13367 const double zpart = Z(atm->p[ip]);
13368 if (atm->lon[ip] < ctl->csi_lon0
13369 || atm->lon[ip] >= ctl->csi_lon1
13370 || atm->lat[ip] < ctl->csi_lat0
13371 || atm->lat[ip] >= ctl->csi_lat1
13372 || zpart < ctl->csi_z0 || zpart >= ctl->csi_z1)
13373 continue;
13374 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
13375 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
13376 const int iz = (int) ((zpart - ctl->csi_z0) / dz);
13377 if (ix >= ctl->csi_nx || iy >= ctl->csi_ny || iz >= ctl->csi_nz)
13378 continue;
13379
13380 /* Get total mass in grid cell... */
13381 const int idx =
13382 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13383 modmean[idx] +=
13384 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13385 }
13386 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
13387 /* Analyze all grid cells... */
13388 for (int ix = 0; ix < ctl->csi_nx; ix++)
13389 for (int iy = 0; iy < ctl->csi_ny; iy++)
13390 for (int iz = 0; iz < ctl->csi_nz; iz++) {
13391
13392 /* Calculate mean observation index... */
13393 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13394 if (e == 0)
13395 if (obscount[idx]) {
13396 obsmean[idx] /= obscount[idx];
13397 obsstd[idx] =
13398 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
13399 }
13400
13401 /* Calculate model mean per ensemble... */
13402 const int midx = e * grid_size + idx;
13403 if (modmean[midx] > 0)
13404 modmean[midx] /= (1e6 * area[iy]);
13405
13406 /* Check number of observations... */
13407 if (obscount[idx]) {
13408
13409 /* Calculate CSI... */
13410 ct[e]++;
13411 if (obsmean[idx] >= ctl->csi_obsmin
13412 && modmean[midx] >= ctl->csi_modmin)
13413 cx[e]++;
13414 else if (obsmean[idx] >= ctl->csi_obsmin)
13415 cy[e]++;
13416 else if (modmean[midx] >= ctl->csi_modmin)
13417 cz[e]++;
13418
13419 /* Save data for other verification statistics... */
13420 if (obsmean[idx] >= ctl->csi_obsmin
13421 || modmean[midx] >= ctl->csi_modmin) {
13422 x[n[e]] = modmean[midx];
13423 y[n[e]] = obsmean[idx];
13424 if (modmean[midx] >= ctl->csi_modmin)
13425 obsstdn[n[e]] = obsstd[idx];
13426 if ((++n[e]) >= NCSI)
13427 ERRMSG("Too many points for statistics!");
13428 }
13429 }
13430 }
13431 /* Write output... */
13432 if (fmod(t, ctl->csi_dt_out) == 0) {
13433
13434 if (n[e] == 0)
13435 continue;
13436
13437 /* Calculate verification statistics
13438 (https://www.cawcr.gov.au/projects/verification/) ... */
13439 static double work[2 * NCSI], work2[2 * NCSI];
13440 const int n_obs = cx[e] + cy[e];
13441 const int n_for = cx[e] + cz[e];
13442 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
13443 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
13444 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
13445 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
13446 const double csi =
13447 (cx[e] + cy[e] + cz[e] >
13448 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
13449 const double ets =
13450 (cx[e] + cy[e] + cz[e] - cx_rd >
13451 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
13452 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
13453 const double rho_s =
13454 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
13455 for (int i = 0; i < n[e]; i++) {
13456 work[i] = x[i] - y[i];
13457 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
13458 }
13459 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
13460 const double rmse =
13461 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
13462 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
13463 const double loglikelihood =
13464 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
13465
13466 /* Write... */
13467 fprintf(out,
13468 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
13469 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
13470 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
13471 loglikelihood, n[e]);
13472
13473 /* Set counters to zero... */
13474 for (int i = 0; i < n[e]; i++)
13475 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
13476 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
13477 }
13478 }
13479 /* Free... */
13480 free(modmean);
13481 free(obsmean);
13482 free(obscount);
13483 free(obsstd);
13484
13485 /* Finalize... */
13486 if (t == ctl->t_stop) {
13487
13488 /* Close output file... */
13489 fclose(out);
13490
13491 /* Free... */
13492 free(area);
13493 free(rt);
13494 free(rz);
13495 free(rlon);
13496 free(rlat);
13497 free(robs);
13498 }
13499}
void read_obs(const char *filename, const ctl_t *ctl, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
Reads observation data from a file and stores it in arrays.
Definition: mptrac.c:12361
void read_kernel(const char *filename, double kz[EP], double kw[EP], int *nk)
Reads kernel function data from a file and populates the provided arrays.
Definition: mptrac.c:8871
double kernel_weight(const double kz[EP], const double kw[EP], const int nk, const double p)
Calculates the kernel weight based on altitude and given kernel data.
Definition: mptrac.c:3298
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:583
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:578
Here is the call graph for this function:

◆ write_ens()

void write_ens ( const char *  filename,
const ctl_t ctl,
const atm_t atm,
const double  t 
)

Writes ensemble data to a file.

The write_ens function processes air parcel data to calculate ensemble means and standard deviations for various quantities and writes them to a specified output file. It handles ensemble members and calculates statistics such as means and standard deviations for each ensemble, along with latitude, longitude, altitude, and time information.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.
tA double representing the current time.

The function performs the following steps:

  • Initializes resources and sets up necessary variables.
  • Sets a time interval for processing data.
  • Loops over air parcels to accumulate means and standard deviations for each ensemble member.
  • Creates an output file and writes header information.
  • Writes ensemble data, including time, altitude, latitude, longitude, means, standard deviations, and the number of members.
  • Closes the output file.
Author
Lars Hoffmann

Definition at line 13503 of file mptrac.c.

13507 {
13508
13509 if (ctl->met_coord_type != 0)
13510 ERRMSG("Only lat/lon grid supported");
13511
13512 static FILE *out;
13513
13514 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
13515 x[3], zm[NENS];
13516
13517 static int n[NENS];
13518
13519 /* Set timer... */
13520 SELECT_TIMER("WRITE_ENS", "OUTPUT");
13521
13522 /* Check quantities... */
13523 if (ctl->qnt_ens < 0)
13524 ERRMSG("Missing ensemble IDs!");
13525
13526 /* Set time interval... */
13527 const double t0 = t - 0.5 * ctl->dt_mod;
13528 const double t1 = t + 0.5 * ctl->dt_mod;
13529
13530 /* Init... */
13531 for (int i = 0; i < NENS; i++) {
13532 for (int iq = 0; iq < ctl->nq; iq++)
13533 qm[iq][i] = qs[iq][i] = 0;
13534 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
13535 n[i] = 0;
13536 }
13537
13538 /* Loop over air parcels... */
13539 for (int ip = 0; ip < atm->np; ip++) {
13540
13541 /* Check time... */
13542 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13543 continue;
13544
13545 /* Check ensemble ID... */
13546 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
13547 ERRMSG("Ensemble ID is out of range!");
13548
13549 /* Get means... */
13550 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
13551 for (int iq = 0; iq < ctl->nq; iq++) {
13552 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
13553 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
13554 }
13555 xm[ctl->qnt_ens][0] += x[0];
13556 xm[ctl->qnt_ens][1] += x[1];
13557 xm[ctl->qnt_ens][2] += x[2];
13558 zm[ctl->qnt_ens] += Z(atm->p[ip]);
13559 n[ctl->qnt_ens]++;
13560 }
13561
13562 /* Create file... */
13563 LOG(1, "Write ensemble data: %s", filename);
13564 if (!(out = fopen(filename, "w")))
13565 ERRMSG("Cannot create file!");
13566
13567 /* Write header... */
13568 fprintf(out,
13569 "# $1 = time [s]\n"
13570 "# $2 = altitude [km]\n"
13571 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13572 for (int iq = 0; iq < ctl->nq; iq++)
13573 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
13574 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13575 for (int iq = 0; iq < ctl->nq; iq++)
13576 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
13577 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13578 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
13579
13580 /* Write data... */
13581 for (int i = 0; i < NENS; i++)
13582 if (n[i] > 0) {
13583 cart2geo(xm[i], &dummy, &lon, &lat);
13584 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
13585 for (int iq = 0; iq < ctl->nq; iq++) {
13586 fprintf(out, " ");
13587 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
13588 }
13589 for (int iq = 0; iq < ctl->nq; iq++) {
13590 fprintf(out, " ");
13591 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
13592 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
13593 }
13594 fprintf(out, " %d\n", n[i]);
13595 }
13596
13597 /* Close file... */
13598 fclose(out);
13599}
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
Here is the call graph for this function:

◆ write_depo()

void write_depo ( const char *  filename,
const ctl_t ctl,
const depo_t depo,
const double  t 
)

Convert cumulative ground inventories to Bq m^-2 and write them.

Cell centers and areas are derived from GRID_LON*, GRID_LAT*, GRID_NX, and GRID_NY. If RADIO_DECAY is enabled, inventories are decayed to t. Output format is selected by DEPO_TYPE.

Parameters
[in]filenameOutput filename.
[in]ctlGrid, format, compression, and decay settings.
[in]depoCumulative radionuclide inventories.
[in]tOutput validity time [s since 2000-01-01 00:00 UTC].

Definition at line 13603 of file mptrac.c.

13607 {
13608
13609 double *area, *data, *lat, *lon;
13610
13611 /* Set timer... */
13612 SELECT_TIMER("WRITE_DEPO", "OUTPUT");
13613 LOG(1, "Write radioactive deposition data: %s", filename);
13614
13615 /* Allocate output arrays... */
13616 const int nxy = ctl->grid_nx * ctl->grid_ny;
13617 ALLOC(area, double,
13618 ctl->grid_ny);
13619 ALLOC(data, double,
13620 4 * nxy);
13621 ALLOC(lat, double,
13622 ctl->grid_ny);
13623 ALLOC(lon, double,
13624 ctl->grid_nx);
13625
13626 /* Set horizontal coordinates and grid-cell areas... */
13627 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
13628 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
13629 for (int ix = 0; ix < ctl->grid_nx; ix++)
13630 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
13631 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13632 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
13633 area[iy] = 1e6 * dlat * dlon * SQR(RE * M_PI / 180.)
13634 * cos(DEG2RAD(lat[iy]));
13635 }
13636
13637 /* Convert inventories to activity densities at output time... */
13638 const double lambda[4] = {
13639 log(2.0) / RADIO_HALF_LIFE_PB210,
13640 log(2.0) / RADIO_HALF_LIFE_BE7,
13641 log(2.0) / RADIO_HALF_LIFE_CS137,
13642 log(2.0) / RADIO_HALF_LIFE_I131
13643 };
13644 const double *inventory[4] = {
13645 depo->Apb210, depo->Abe7, depo->Acs137, depo->Ai131
13646 };
13647 for (int iq = 0; iq < 4; iq++) {
13648 const double decay = ctl->radio_decay
13649 ? exp(-lambda[iq] * (t - ctl->t_start)) : 1.0;
13650 for (int ix = 0; ix < ctl->grid_nx; ix++)
13651 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13652 const int idx = ARRAY_2D(ix, iy, ctl->grid_ny);
13653 data[iq * nxy + idx] = inventory[iq][idx] * decay / area[iy];
13654 }
13655 }
13656
13657 /* Write output... */
13658 if (ctl->depo_type == 0)
13659 write_depo_asc(filename, ctl, data, t, lon, lat, area);
13660 else if (ctl->depo_type == 1)
13661 write_depo_nc(filename, ctl, data, t, lon, lat, area);
13662 else
13663 ERRMSG("Radioactive deposition output type unknown!");
13664
13665 /* Free... */
13666 free(area);
13667 free(data);
13668 free(lat);
13669 free(lon);
13670}
void write_depo_asc(const char *filename, const ctl_t *ctl, const double *data, const double t, const double *lon, const double *lat, const double *area)
Write radioactive deposition densities as a gnuplot-compatible table.
Definition: mptrac.c:13674
void write_depo_nc(const char *filename, const ctl_t *ctl, const double *data, const double t, const double *lon, const double *lat, const double *area)
Write radioactive deposition densities as a CF-style netCDF file.
Definition: mptrac.c:13714
Here is the call graph for this function:

◆ write_depo_asc()

void write_depo_asc ( const char *  filename,
const ctl_t ctl,
const double *  data,
const double  t,
const double *  lon,
const double *  lat,
const double *  area 
)

Write radioactive deposition densities as a gnuplot-compatible table.

Parameters
[in]filenameOutput filename.
[in]ctlDeposition grid dimensions.
[in]dataFour consecutive fields in Bq m^-2.
[in]tOutput validity time [s since 2000-01-01 00:00 UTC].
[in]lonGrid-cell center longitudes [deg].
[in]latGrid-cell center latitudes [deg].
[in]areaGrid-cell areas by latitude [m^2].

Definition at line 13674 of file mptrac.c.

13681 {
13682
13683 FILE *out;
13684 if (!(out = fopen(filename, "w")))
13685 ERRMSG("Cannot create file!");
13686
13687 fprintf(out,
13688 "# $1 = time [s]\n"
13689 "# $2 = longitude [deg]\n"
13690 "# $3 = latitude [deg]\n"
13691 "# $4 = area [m^2]\n"
13692 "# $5 = deposited Pb-210 activity [Bq/m^2]\n"
13693 "# $6 = deposited Be-7 activity [Bq/m^2]\n"
13694 "# $7 = deposited Cs-137 activity [Bq/m^2]\n"
13695 "# $8 = deposited I-131 activity [Bq/m^2]\n\n");
13696
13697 const int nxy = ctl->grid_nx * ctl->grid_ny;
13698 for (int ix = 0; ix < ctl->grid_nx; ix++) {
13699 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13700 const int idx = ARRAY_2D(ix, iy, ctl->grid_ny);
13701 fprintf(out, "%.2f %g %g %g %g %g %g %g\n",
13702 t, lon[ix], lat[iy], area[iy],
13703 data[idx], data[nxy + idx],
13704 data[2 * nxy + idx], data[3 * nxy + idx]);
13705 }
13706 fprintf(out, "\n");
13707 }
13708
13709 fclose(out);
13710}

◆ write_depo_nc()

void write_depo_nc ( const char *  filename,
const ctl_t ctl,
const double *  data,
const double  t,
const double *  lon,
const double *  lat,
const double *  area 
)

Write radioactive deposition densities as a CF-style netCDF file.

Parameters
[in]filenameOutput filename.
[in]ctlDeposition grid dimensions and netCDF compression setting.
[in]dataFour consecutive fields in Bq m^-2.
[in]tOutput validity time [s since 2000-01-01 00:00 UTC].
[in]lonGrid-cell center longitudes [deg].
[in]latGrid-cell center latitudes [deg].
[in]areaGrid-cell areas by latitude [m^2].

Definition at line 13714 of file mptrac.c.

13721 {
13722
13723 double *help;
13724 int ncid, dimid[3], varid;
13725 size_t start[2], count[2];
13726
13727 const int nxy = ctl->grid_nx * ctl->grid_ny;
13728 ALLOC(help, double,
13729 nxy);
13730
13731 /* Create file and dimensions... */
13732 NC(nc_create(filename, NC_NETCDF4, &ncid));
13733 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
13734 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[1]));
13735 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[2]));
13736
13737 /* Define variables... */
13738 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
13739 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
13740 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[1], "latitude",
13741 "degrees_north", 0, 0);
13742 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[2], "longitude",
13743 "degrees_east", 0, 0);
13744 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[1], "surface area", "m**2", 0, 0);
13745 NC_DEF_VAR("depo_pb210", NC_DOUBLE, 3, dimid,
13746 "ground inventory of Pb-210", "Bq m**-2", ctl->grid_nc_level, 0);
13747 NC_DEF_VAR("depo_be7", NC_DOUBLE, 3, dimid,
13748 "ground inventory of Be-7", "Bq m**-2", ctl->grid_nc_level, 0);
13749 NC_DEF_VAR("depo_cs137", NC_DOUBLE, 3, dimid,
13750 "ground inventory of Cs-137", "Bq m**-2", ctl->grid_nc_level, 0);
13751 NC_DEF_VAR("depo_i131", NC_DOUBLE, 3, dimid,
13752 "ground inventory of aerosol-bound I-131", "Bq m**-2",
13753 ctl->grid_nc_level, 0);
13754 NC(nc_enddef(ncid));
13755
13756 /* Write coordinates... */
13757 NC_PUT_DOUBLE("time", &t, 0);
13758 NC_PUT_DOUBLE("lon", lon, 0);
13759 NC_PUT_DOUBLE("lat", lat, 0);
13760 NC_PUT_DOUBLE("area", area, 0);
13761
13762 /* Write fields in netCDF dimension order... */
13763 const char *varname[4] = {
13764 "depo_pb210", "depo_be7", "depo_cs137", "depo_i131"
13765 };
13766 for (int iq = 0; iq < 4; iq++) {
13767 for (int ix = 0; ix < ctl->grid_nx; ix++)
13768 for (int iy = 0; iy < ctl->grid_ny; iy++)
13769 help[ARRAY_2D(iy, ix, ctl->grid_nx)] =
13770 data[iq * nxy + ARRAY_2D(ix, iy, ctl->grid_ny)];
13771 NC_PUT_DOUBLE(varname[iq], help, 0);
13772 }
13773
13774 NC(nc_close(ncid));
13775 free(help);
13776}

◆ write_grid()

void write_grid ( const char *  filename,
const ctl_t ctl,
met_t met0,
met_t met1,
const atm_t atm,
const double  t 
)

Writes grid data to a file in ASCII or netCDF format.

The write_grid function processes air parcel data to calculate various grid-based statistics such as column density, mean, and standard deviation for specified quantities. It then writes this data to a specified output file either in ASCII or netCDF format based on the configuration parameters provided in the ctl structure.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
met0A pointer to a met_t structure containing meteorological data for the initial time step.
met1A pointer to a met_t structure containing meteorological data for the final time step.
atmA pointer to an atm_t structure containing atmospheric data.
tA double representing the current time.

The function performs the following steps:

  • Initializes resources and sets up necessary variables.
  • Reads kernel data if it is specified in the control parameters.
  • Allocates memory for various arrays to store grid data.
  • Determines the grid box size and sets up vertical and horizontal coordinates.
  • Sets a time interval for output data processing.
  • Calculates grid box indices for atmospheric model data.
  • Averages data within each grid box.
  • Calculates column density and volume mixing ratio.
  • Writes data to the output file either in ASCII or netCDF format based on the specified grid_type in the control parameters.
  • Frees allocated memory.
Note
The function supports parallel processing using OpenMP for certain computational tasks to improve performance.
Author
Lars Hoffmann

Definition at line 13780 of file mptrac.c.

13786 {
13787
13788 if (ctl->met_coord_type != 0)
13789 ERRMSG("Only lat/lon grid supported");
13790
13791 static double kz[EP], kw[EP];
13792
13793 static int nk;
13794
13795 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
13796
13797 int *ixs, *iys, *izs, *np;
13798
13799 /* Set timer... */
13800 SELECT_TIMER("WRITE_GRID", "OUTPUT");
13801
13802 /* Write info... */
13803 LOG(1, "Write grid data: %s", filename);
13804
13805 /* Init... */
13806 if (t == ctl->t_start) {
13807
13808 /* Read kernel data... */
13809 if (ctl->grid_kernel[0] != '-')
13810 read_kernel(ctl->grid_kernel, kz, kw, &nk);
13811 }
13812
13813 /* Allocate... */
13814 ALLOC(cd, double,
13815 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13816 for (int iq = 0; iq < ctl->nq; iq++) {
13817 ALLOC(mean[iq], double,
13818 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13819 ALLOC(sigma[iq], double,
13820 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13821 }
13822 ALLOC(vmr_impl, double,
13823 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13824 ALLOC(z, double,
13825 ctl->grid_nz);
13826 ALLOC(lon, double,
13827 ctl->grid_nx);
13828 ALLOC(lat, double,
13829 ctl->grid_ny);
13830 ALLOC(area, double,
13831 ctl->grid_ny);
13832 ALLOC(press, double,
13833 ctl->grid_nz);
13834 ALLOC(np, int,
13835 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13836 ALLOC(ixs, int,
13837 atm->np);
13838 ALLOC(iys, int,
13839 atm->np);
13840 ALLOC(izs, int,
13841 atm->np);
13842
13843 /* Set grid box size... */
13844 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
13845 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
13846 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
13847
13848 /* Set vertical coordinates... */
13849#pragma omp parallel for default(shared)
13850 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13851 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
13852 press[iz] = P(z[iz]);
13853 }
13854
13855 /* Set horizontal coordinates... */
13856 for (int ix = 0; ix < ctl->grid_nx; ix++)
13857 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
13858#pragma omp parallel for default(shared)
13859 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13860 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
13861 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13862 }
13863
13864 /* Set time interval for output... */
13865 const double t0 = t - 0.5 * ctl->dt_mod;
13866 const double t1 = t + 0.5 * ctl->dt_mod;
13867
13868 /* Get grid box indices... */
13869#pragma omp parallel for default(shared)
13870 for (int ip = 0; ip < atm->np; ip++) {
13871 const double zpart = Z(atm->p[ip]);
13872 if (atm->time[ip] < t0 || atm->time[ip] > t1
13873 || atm->lon[ip] < ctl->grid_lon0
13874 || atm->lon[ip] >= ctl->grid_lon1
13875 || atm->lat[ip] < ctl->grid_lat0
13876 || atm->lat[ip] >= ctl->grid_lat1
13877 || zpart < ctl->grid_z0 || zpart >= ctl->grid_z1) {
13878 izs[ip] = -1;
13879 continue;
13880 }
13881 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
13882 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
13883 izs[ip] = (int) ((zpart - ctl->grid_z0) / dz);
13884 if (ixs[ip] >= ctl->grid_nx || iys[ip] >= ctl->grid_ny
13885 || izs[ip] >= ctl->grid_nz)
13886 izs[ip] = -1;
13887 }
13888
13889 /* Average data... */
13890 for (int ip = 0; ip < atm->np; ip++)
13891 if (izs[ip] >= 0) {
13892 const int idx =
13893 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
13894 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
13895 np[idx]++;
13896 for (int iq = 0; iq < ctl->nq; iq++) {
13897 mean[iq][idx] += kernel * atm->q[iq][ip];
13898 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
13899 }
13900 }
13901
13902 /* Calculate column density and volume mixing ratio... */
13903#pragma omp parallel for default(shared)
13904 for (int ix = 0; ix < ctl->grid_nx; ix++)
13905 for (int iy = 0; iy < ctl->grid_ny; iy++)
13906 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13907
13908 /* Get grid index... */
13909 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
13910
13911 /* Calculate column density... */
13912 cd[idx] = NAN;
13913 if (ctl->qnt_m >= 0)
13914 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
13915
13916 /* Calculate volume mixing ratio (implicit)... */
13917 vmr_impl[idx] = NAN;
13918 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
13919 && met1 != NULL) {
13920 vmr_impl[idx] = 0;
13921 if (mean[ctl->qnt_m][idx] > 0) {
13922
13923 /* Get temperature... */
13924 double temp;
13926 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
13927 lon[ix], lat[iy], &temp, ci, cw, 1);
13928
13929 /* Calculate volume mixing ratio... */
13930 vmr_impl[idx] =
13931 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
13932 }
13933 }
13934
13935 /* Calculate mean... */
13936 if (np[idx] > 0)
13937 for (int iq = 0; iq < ctl->nq; iq++) {
13938 mean[iq][idx] /= np[idx];
13939 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
13940 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
13941 } else
13942 for (int iq = 0; iq < ctl->nq; iq++) {
13943 mean[iq][idx] = NAN;
13944 sigma[iq][idx] = NAN;
13945 }
13946 }
13947
13948 /* Write ASCII data... */
13949 if (ctl->grid_type == 0)
13950 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
13951 t, z, lon, lat, area, dz, np);
13952
13953 /* Write netCDF data... */
13954 else if (ctl->grid_type == 1)
13955 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
13956 t, z, lon, lat, area, dz, np);
13957
13958 /* Error message... */
13959 else
13960 ERRMSG("Grid data format GRID_TYPE unknown!");
13961
13962 /* Free... */
13963 free(cd);
13964 for (int iq = 0; iq < ctl->nq; iq++) {
13965 free(mean[iq]);
13966 free(sigma[iq]);
13967 }
13968 free(vmr_impl);
13969 free(z);
13970 free(lon);
13971 free(lat);
13972 free(area);
13973 free(press);
13974 free(np);
13975 free(ixs);
13976 free(iys);
13977 free(izs);
13978}
void write_grid_asc(const char *filename, const ctl_t *ctl, const double *cd, double *mean[NQ], double *sigma[NQ], const double *vmr_impl, const double t, const double *z, const double *lon, const double *lat, const double *area, const double dz, const int *np)
Writes grid data to an ASCII file.
Definition: mptrac.c:13982
void write_grid_nc(const char *filename, const ctl_t *ctl, const double *cd, double *mean[NQ], double *sigma[NQ], const double *vmr_impl, const double t, const double *z, const double *lon, const double *lat, const double *area, const double dz, const int *np)
Writes grid data to a NetCDF file.
Definition: mptrac.c:14086
Here is the call graph for this function:

◆ write_grid_asc()

void write_grid_asc ( const char *  filename,
const ctl_t ctl,
const double *  cd,
double *  mean[NQ],
double *  sigma[NQ],
const double *  vmr_impl,
const double  t,
const double *  z,
const double *  lon,
const double *  lat,
const double *  area,
const double  dz,
const int *  np 
)

Writes grid data to an ASCII file.

The write_grid_asc function writes gridded air parcel data, including column density, mean and standard deviation for specified quantities, and volume mixing ratio (if available), to an ASCII file. The function also supports writing gnuplot commands to generate plots if requested in the control parameters.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
cdAn array of doubles representing column density values.
meanAn array of arrays of doubles representing the mean values for specified quantities.
sigmaAn array of arrays of doubles representing the standard deviation values for specified quantities.
vmr_implAn array of doubles representing the volume mixing ratio (implicit) values.
tA double representing the current time.
zAn array of doubles representing vertical coordinates (altitude).
lonAn array of doubles representing longitudinal coordinates.
latAn array of doubles representing latitudinal coordinates.
areaAn array of doubles representing surface area values.
dzA double representing the layer depth.
npAn array of integers representing the number of particles.

The function performs the following steps:

  • Checks if gnuplot output is requested in the control parameters and sets up a gnuplot pipe if needed.
  • If gnuplot output is requested, sets the plot filename and time string, and dumps gnuplot file contents to the pipe.
  • Otherwise, creates the output file for writing in ASCII format.
  • Writes the header information to the output file, including column labels.
  • Writes the grid data to the output file, including time, altitude, coordinates, surface area, layer depth, column density, volume mixing ratio, number of particles, mean values for specified quantities, and standard deviation values if requested.
  • Closes the output file.
Note
The function supports writing gnuplot commands to generate plots if requested in the control parameters. It also supports writing mean and standard deviation values for specified quantities if requested.
Author
Lars Hoffmann

Definition at line 13982 of file mptrac.c.

13995 {
13996
13997 FILE *out;
13998
13999 /* Check if gnuplot output is requested... */
14000 if (ctl->grid_gpfile[0] != '-') {
14001
14002 /* Create gnuplot pipe... */
14003 if (!(out = popen("gnuplot", "w")))
14004 ERRMSG("Cannot create pipe to gnuplot!");
14005
14006 /* Set plot filename... */
14007 fprintf(out, "set out \"%s.png\"\n", filename);
14008
14009 /* Set time string... */
14010 double r;
14011 int year, mon, day, hour, min, sec;
14012 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
14013 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
14014 year, mon, day, hour, min);
14015
14016 /* Dump gnuplot file to pipe... */
14017 FILE *in;
14018 char line[LEN];
14019 if (!(in = fopen(ctl->grid_gpfile, "r")))
14020 ERRMSG("Cannot open file!");
14021 while (fgets(line, LEN, in))
14022 fprintf(out, "%s", line);
14023 fclose(in);
14024 }
14025
14026 else {
14027
14028 /* Create file... */
14029 if (!(out = fopen(filename, "w")))
14030 ERRMSG("Cannot create file!");
14031 }
14032
14033 /* Write header... */
14034 fprintf(out,
14035 "# $1 = time [s]\n"
14036 "# $2 = altitude [km]\n"
14037 "# $3 = longitude [deg]\n"
14038 "# $4 = latitude [deg]\n"
14039 "# $5 = surface area [km^2]\n"
14040 "# $6 = layer depth [km]\n"
14041 "# $7 = column density (implicit) [kg/m^2]\n"
14042 "# $8 = volume mixing ratio (implicit) [ppv]\n"
14043 "# $9 = number of particles [1]\n");
14044 for (int iq = 0; iq < ctl->nq; iq++)
14045 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
14046 ctl->qnt_unit[iq]);
14047 if (ctl->grid_stddev)
14048 for (int iq = 0; iq < ctl->nq; iq++)
14049 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
14050 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
14051 fprintf(out, "\n");
14052
14053 /* Write data... */
14054 for (int ix = 0; ix < ctl->grid_nx; ix++) {
14055 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
14056 fprintf(out, "\n");
14057 for (int iy = 0; iy < ctl->grid_ny; iy++) {
14058 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
14059 fprintf(out, "\n");
14060 for (int iz = 0; iz < ctl->grid_nz; iz++) {
14061 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
14062 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
14063 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
14064 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
14065 for (int iq = 0; iq < ctl->nq; iq++) {
14066 fprintf(out, " ");
14067 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
14068 }
14069 if (ctl->grid_stddev)
14070 for (int iq = 0; iq < ctl->nq; iq++) {
14071 fprintf(out, " ");
14072 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
14073 }
14074 fprintf(out, "\n");
14075 }
14076 }
14077 }
14078 }
14079
14080 /* Close file... */
14081 fclose(out);
14082}
Here is the call graph for this function:

◆ write_grid_nc()

void write_grid_nc ( const char *  filename,
const ctl_t ctl,
const double *  cd,
double *  mean[NQ],
double *  sigma[NQ],
const double *  vmr_impl,
const double  t,
const double *  z,
const double *  lon,
const double *  lat,
const double *  area,
const double  dz,
const int *  np 
)

Writes grid data to a NetCDF file.

The write_grid_nc function writes gridded air parcel data, including column density, mean and standard deviation for specified quantities, and volume mixing ratio (if available), to a NetCDF file. NetCDF is a self-describing, machine-independent data format for storing scientific data.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
cdAn array of doubles representing column density values.
meanAn array of arrays of doubles representing the mean values for specified quantities.
sigmaAn array of arrays of doubles representing the standard deviation values for specified quantities.
vmr_implAn array of doubles representing the volume mixing ratio (implicit) values.
tA double representing the current time.
zAn array of doubles representing vertical coordinates (altitude).
lonAn array of doubles representing longitudinal coordinates.
latAn array of doubles representing latitudinal coordinates.
areaAn array of doubles representing surface area values.
dzA double representing the layer depth.
npAn array of integers representing the number of particles.

The function performs the following steps:

  • Allocates memory for temporary arrays required for writing data.
  • Creates a NetCDF file with the specified filename.
  • Defines dimensions and variables in the NetCDF file, along with their attributes.
  • Writes the data arrays to the NetCDF file.
  • Closes the NetCDF file.
  • Frees allocated memory.
Note
NetCDF files are commonly used in scientific computing and can be accessed by various programming languages and software packages. Additionally, the function supports writing mean and standard deviation values for specified quantities if requested.
Author
Lars Hoffmann

Definition at line 14086 of file mptrac.c.

14099 {
14100
14101 char longname[2 * LEN], varname[2 * LEN];
14102
14103 double *help;
14104
14105 int *help2, ncid, dimid[10], varid;
14106
14107 size_t start[2], count[2];
14108
14109 /* Allocate... */
14110 ALLOC(help, double,
14111 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
14112 ALLOC(help2, int,
14113 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
14114
14115 /* Create file... */
14116 NC(nc_create(filename, NC_NETCDF4, &ncid));
14117
14118 /* Define dimensions... */
14119 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
14120 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
14121 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
14122 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
14123 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
14124
14125 /* Define variables and their attributes... */
14126 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
14127 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
14128 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
14129 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
14130 0);
14131 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
14132 0);
14133 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
14134 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
14135
14136 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
14137 ctl->grid_nc_level, 0);
14138 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
14139 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
14140 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
14141 for (int iq = 0; iq < ctl->nq; iq++) {
14142 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
14143 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
14144 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
14145 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
14146 if (ctl->grid_stddev) {
14147 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
14148 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
14149 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
14150 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
14151 }
14152 }
14153 /* End definitions... */
14154 NC(nc_enddef(ncid));
14155
14156 /* Write data... */
14157 NC_PUT_DOUBLE("time", &t, 0);
14158 NC_PUT_DOUBLE("lon", lon, 0);
14159 NC_PUT_DOUBLE("lat", lat, 0);
14160 NC_PUT_DOUBLE("z", z, 0);
14161 NC_PUT_DOUBLE("area", area, 0);
14162 NC_PUT_DOUBLE("dz", &dz, 0);
14163
14164 for (int ix = 0; ix < ctl->grid_nx; ix++)
14165 for (int iy = 0; iy < ctl->grid_ny; iy++)
14166 for (int iz = 0; iz < ctl->grid_nz; iz++)
14167 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14168 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14169 NC_PUT_DOUBLE("cd", help, 0);
14170
14171 for (int ix = 0; ix < ctl->grid_nx; ix++)
14172 for (int iy = 0; iy < ctl->grid_ny; iy++)
14173 for (int iz = 0; iz < ctl->grid_nz; iz++)
14174 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14175 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14176 NC_PUT_DOUBLE("vmr_impl", help, 0);
14177
14178 for (int ix = 0; ix < ctl->grid_nx; ix++)
14179 for (int iy = 0; iy < ctl->grid_ny; iy++)
14180 for (int iz = 0; iz < ctl->grid_nz; iz++)
14181 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14182 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14183 NC_PUT_INT("np", help2, 0);
14184
14185 for (int iq = 0; iq < ctl->nq; iq++) {
14186 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
14187 for (int ix = 0; ix < ctl->grid_nx; ix++)
14188 for (int iy = 0; iy < ctl->grid_ny; iy++)
14189 for (int iz = 0; iz < ctl->grid_nz; iz++)
14190 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14191 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14192 NC_PUT_DOUBLE(varname, help, 0);
14193 }
14194
14195 if (ctl->grid_stddev)
14196 for (int iq = 0; iq < ctl->nq; iq++) {
14197 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
14198 for (int ix = 0; ix < ctl->grid_nx; ix++)
14199 for (int iy = 0; iy < ctl->grid_ny; iy++)
14200 for (int iz = 0; iz < ctl->grid_nz; iz++)
14201 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14202 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14203 NC_PUT_DOUBLE(varname, help, 0);
14204 }
14205
14206 /* Close file... */
14207 NC(nc_close(ncid));
14208
14209 /* Free... */
14210 free(help);
14211 free(help2);
14212}
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1667

◆ write_met_bin()

void write_met_bin ( const char *  filename,
const ctl_t ctl,
met_t met 
)

Writes meteorological data in binary format to a specified file.

This function writes meteorological data from the met_t structure to a binary file. The data includes grid and surface data, as well as multi-level data such as temperature, velocity components, and atmospheric properties. The compression options for multi-level data (ZFP) are controlled via the ctl_t structure. The function supports multiple variables, such as surface pressure, temperature, wind components, and cloud properties.

Parameters
filenameA constant character pointer representing the name of the file to write the binary data to.
ctlA pointer to a ctl_t structure, which holds control parameters including the type of meteorological data, compression settings, and grid dimensions.
metA pointer to a met_t structure that contains the meteorological data to be written to the binary file.
Note
  • The function creates a new file to write the data. If the file cannot be created, an error is generated.
  • The type of meteorological data (ctl->met_type) and the version of the binary format are written at the beginning of the file.
  • Grid data such as longitude, latitude, pressure levels, and time are written to the file.
  • Surface data (e.g., pressure, temperature, wind components) are written using the write_met_bin_2d helper function.
  • Multi-level (3D) data such as geopotential height, temperature, and wind velocity are written using the write_met_bin_3d function with optional ZFP compression settings.
Author
Lars Hoffmann

Definition at line 14216 of file mptrac.c.

14219 {
14220
14221 /* Create file... */
14222 FILE *out, *level_log = NULL;
14223 if (!(out = fopen(filename, "w")))
14224 ERRMSG("Cannot create file!");
14225
14226 /* Create diagnostics file... */
14227 if (strcmp(ctl->met_comp_logfile, "-") != 0) {
14228
14229 if (!(level_log = fopen(ctl->met_comp_logfile, "w")))
14230 ERRMSG("Cannot create compression log file!");
14231 LOG(1, "Write compression diagnostics: %s", ctl->met_comp_logfile);
14232
14233 /* Write header... */
14234 fprintf(level_log,
14235 "# $1 = compression codec name [-]\n"
14236 "# $2 = variable name [-]\n"
14237 "# $3 = level index [-]\n"
14238 "# $4 = pressure level [hPa]\n"
14239 "# $5 = compression ratio [-]\n"
14240 "# $6 = bits per value [bit/value]\n"
14241 "# $7 = correlation coefficient [-]\n"
14242 "# $8 = mean compression error [-]\n"
14243 "# $9 = standard deviation of compression error [-]\n"
14244 "# $10 = minimum compression error [-]\n"
14245 "# $11 = maximum compression error [-]\n"
14246 "# $12 = mean value of original field [-]\n"
14247 "# $13 = value range of original field [-]\n"
14248 "# $14 = normalized root mean square error [-]\n"
14249 "# $15 = compression time [s]\n"
14250 "# $16 = compression speed [MiB/s]\n"
14251 "# $17 = decompression time [s]\n"
14252 "# $18 = decompression speed [MiB/s]\n\n");
14253 }
14254
14255 /* Write type of binary data... */
14256 FWRITE(&ctl->met_type, int,
14257 1,
14258 out);
14259
14260 /* Write version of binary data... */
14261 int version = 104;
14262 FWRITE(&version, int,
14263 1,
14264 out);
14265
14266 /* Write grid data... */
14267 FWRITE(&met->time, double,
14268 1,
14269 out);
14270 FWRITE(&met->nx, int,
14271 1,
14272 out);
14273 FWRITE(&met->ny, int,
14274 1,
14275 out);
14276 FWRITE(&met->np, int,
14277 1,
14278 out);
14279 FWRITE(met->lon, double,
14280 (size_t) met->nx,
14281 out);
14282 FWRITE(met->lat, double,
14283 (size_t) met->ny,
14284 out);
14285 FWRITE(met->p, double,
14286 (size_t) met->np,
14287 out);
14288
14289 /* Write surface data... */
14290 write_met_bin_2d(out, met, met->ps, "PS");
14291 write_met_bin_2d(out, met, met->ts, "TS");
14292 write_met_bin_2d(out, met, met->zs, "ZS");
14293 write_met_bin_2d(out, met, met->us, "US");
14294 write_met_bin_2d(out, met, met->vs, "VS");
14295 write_met_bin_2d(out, met, met->ess, "ESS");
14296 write_met_bin_2d(out, met, met->nss, "NSS");
14297 write_met_bin_2d(out, met, met->shf, "SHF");
14298 write_met_bin_2d(out, met, met->lsm, "LSM");
14299 write_met_bin_2d(out, met, met->sst, "SST");
14300 write_met_bin_2d(out, met, met->pbl, "PBL");
14301 write_met_bin_2d(out, met, met->pt, "PT");
14302 write_met_bin_2d(out, met, met->tt, "TT");
14303 write_met_bin_2d(out, met, met->zt, "ZT");
14304 write_met_bin_2d(out, met, met->h2ot, "H2OT");
14305 write_met_bin_2d(out, met, met->pct, "PCT");
14306 write_met_bin_2d(out, met, met->pcb, "PCB");
14307 write_met_bin_2d(out, met, met->cl, "CL");
14308 write_met_bin_2d(out, met, met->plcl, "PLCL");
14309 write_met_bin_2d(out, met, met->plfc, "PLFC");
14310 write_met_bin_2d(out, met, met->pel, "PEL");
14311 write_met_bin_2d(out, met, met->cape, "CAPE");
14312 write_met_bin_2d(out, met, met->cin, "CIN");
14313 write_met_bin_2d(out, met, met->o3c, "O3C");
14314
14315 /* Write level data... */
14316 write_met_bin_3d(out, ctl, met, met->z, "Z", 0, level_log);
14317 write_met_bin_3d(out, ctl, met, met->t, "T", 1, level_log);
14318 write_met_bin_3d(out, ctl, met, met->u, "U", 2, level_log);
14319 write_met_bin_3d(out, ctl, met, met->v, "V", 3, level_log);
14320 write_met_bin_3d(out, ctl, met, met->w, "W", 4, level_log);
14321 write_met_bin_3d(out, ctl, met, met->pv, "PV", 5, level_log);
14322 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", 6, level_log);
14323 write_met_bin_3d(out, ctl, met, met->o3, "O3", 7, level_log);
14324 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", 8, level_log);
14325 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", 9, level_log);
14326 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", 10, level_log);
14327 write_met_bin_3d(out, ctl, met, met->swc, "SWC", 11, level_log);
14328 write_met_bin_3d(out, ctl, met, met->cc, "CC", 12, level_log);
14329 if (METVAR != 13)
14330 ERRMSG("Number of meteo variables doesn't match!");
14331
14332 /* Write final flag... */
14333 int final = 999;
14334 FWRITE(&final, int,
14335 1,
14336 out);
14337
14338 /* Close file... */
14339 if (level_log)
14340 fclose(level_log);
14341 fclose(out);
14342}
void write_met_bin_3d(FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int metvar, FILE *level_log)
Writes a 3-dimensional meteorological variable to a binary file.
Definition: mptrac.c:14375
void write_met_bin_2d(FILE *out, met_t *met, float var[EX][EY], const char *varname)
Writes a 2-dimensional meteorological variable to a binary file.
Definition: mptrac.c:14346
Here is the call graph for this function:

◆ write_met_bin_2d()

void write_met_bin_2d ( FILE *  out,
met_t met,
float  var[EX][EY],
const char *  varname 
)

Writes a 2-dimensional meteorological variable to a binary file.

The write_met_bin_2d function writes a 2-dimensional meteorological variable to a binary file specified by the out parameter. The variable data is provided in a 2-dimensional array var with maximum dimensions EX by EY. The variable name is provided as a string in the varname parameter.

Parameters
outA pointer to a FILE structure representing the output file.
metA pointer to a met_t structure containing meteorological data.
varAn array of floats representing the 2-dimensional variable data.
varnameA string containing the name of the variable being written.

The function performs the following steps:

  • Allocates memory for a temporary buffer to hold the variable data.
  • Copies the variable data from the 2-dimensional array var to the temporary buffer help.
  • Writes the uncompressed variable data to the binary file specified by out.
  • Logs a message indicating the successful writing of the variable data.
  • Frees the allocated memory.
Note
This function is typically used to write surface data or other 2-dimensional meteorological variables to a binary file.
Author
Lars Hoffmann

Definition at line 14346 of file mptrac.c.

14350 {
14351
14352 float *help;
14353
14354 /* Allocate... */
14355 ALLOC(help, float,
14356 EX * EY);
14357
14358 /* Copy data... */
14359 for (int ix = 0; ix < met->nx; ix++)
14360 for (int iy = 0; iy < met->ny; iy++)
14361 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
14362
14363 /* Write uncompressed data... */
14364 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
14365 FWRITE(help, float,
14366 (size_t) (met->nx * met->ny),
14367 out);
14368
14369 /* Free... */
14370 free(help);
14371}

◆ write_met_bin_3d()

void write_met_bin_3d ( FILE *  out,
const ctl_t ctl,
met_t met,
float  var[EX][EY][EP],
const char *  varname,
const int  metvar,
FILE *  level_log 
)

Writes a 3-dimensional meteorological variable to a binary file.

The write_met_bin_3d function writes a 3-dimensional meteorological variable to a binary file specified by the out parameter. The variable data is provided in a 3-dimensional array var with maximum dimensions EX by EY by EP. The variable name is provided as a string in the varname parameter. Additionally, the function takes parameters for specifying the compression precision and tolerance.

Parameters
outA pointer to a FILE structure representing the output file.
ctlA pointer to a ctl_t structure containing control parameters.
metA pointer to a met_t structure containing meteorological data.
varAn array of floats representing the 3-dimensional variable data.
varnameA string containing the name of the variable being written.
metvarIndex of the meteorological variable, used to select codec-specific compression settings.
level_logOptional file stream for per-level compression diagnostics, or NULL to disable logging.

The function performs the following steps:

  • Allocates memory for a temporary buffer to hold the variable data.
  • Copies the variable data from the 3-dimensional array var to the temporary buffer help.
  • Writes the variable data to the binary file specified by out using the specified compression method (uncompressed, packed, ZFP, ZSTD, cmultiscale).
  • Logs a message indicating the successful writing of the variable data.
  • Frees the allocated memory.
Note
This function is typically used to write level data or other 3-dimensional meteorological variables to a binary file.
Depending on the value of ctl->met_type, the function writes the variable data using different compression methods. If ctl->met_type is not supported, an error message is logged.
Author
Lars Hoffmann

Definition at line 14375 of file mptrac.c.

14382 {
14383
14384 float *help;
14385
14386 /* Allocate... */
14387 ALLOC(help, float,
14388 EX * EY * EP);
14389
14390 /* Copy data... */
14391#pragma omp parallel for default(shared) collapse(2)
14392 for (int ix = 0; ix < met->nx; ix++)
14393 for (int iy = 0; iy < met->ny; iy++)
14394 for (int ip = 0; ip < met->np; ip++)
14395 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
14396
14397 /* Write uncompressed data... */
14398 if (ctl->met_type == 1) {
14399 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
14400 FWRITE(help, float,
14401 (size_t) (met->nx * met->ny * met->np),
14402 out);
14403 }
14404
14405 /* Write packed data... */
14406 else if (ctl->met_type == 2)
14407 compress_pck(ctl, met, varname, help, 0, level_log, out);
14408
14409 /* Write ZFP data... */
14410#ifdef ZFP
14411 else if (ctl->met_type == 3) {
14412 FWRITE(&ctl->met_zfp_prec[metvar], int,
14413 1,
14414 out);
14415 FWRITE(&ctl->met_zfp_tol[metvar], double,
14416 1,
14417 out);
14418 compress_zfp(ctl, met, varname, help, 0, level_log, out);
14419 }
14420#endif
14421
14422 /* Write zstd data... */
14423#ifdef ZSTD
14424 else if (ctl->met_type == 4)
14425 compress_zstd(ctl, met, varname, help, 0, level_log, out);
14426#endif
14427
14428 /* Write LZ4 data... */
14429#ifdef LZ4
14430 else if (ctl->met_type == 8)
14431 compress_lz4(ctl, met, varname, help, 0, level_log, out);
14432#endif
14433
14434 /* Write cmultiscale data... */
14435#ifdef CMS
14436 else if (ctl->met_type == 5) {
14437 compress_cms(ctl, met, varname, help, 0, level_log, out);
14438 }
14439#endif
14440
14441 /* Write SZ3 data... */
14442#ifdef SZ3
14443 else if (ctl->met_type == 7) {
14444 FWRITE(&ctl->met_sz3_prec[metvar], int,
14445 1,
14446 out);
14447 FWRITE(&ctl->met_sz3_tol[metvar], double,
14448 1,
14449 out);
14450 compress_sz3(ctl, met, varname, help, 0, level_log, out);
14451 }
14452#endif
14453
14454 /* Unknown method... */
14455 else {
14456 ERRMSG("MET_TYPE not supported!");
14457
14458 /* This will never execute, hack to avoid compilation error... */
14459 LOG(3, "%d", metvar);
14460 }
14461
14462 /* Free... */
14463 free(help);
14464}
Here is the call graph for this function:

◆ write_met_nc()

void write_met_nc ( const char *  filename,
const ctl_t ctl,
met_t met 
)

Writes meteorological data to a NetCDF file.

This function creates and writes meteorological data to a NetCDF file in the NetCDF-4 format. It defines the required dimensions, grid, surface variables, and level data within the NetCDF structure and writes the corresponding values from the met_t structure. The function uses helper functions to write 2D surface and 3D level data.

Parameters
filenameA constant character pointer representing the name of the NetCDF file to create and write the data to.
ctlA pointer to a ctl_t structure that contains control parameters, such as the NetCDF level and quantization settings.
metA pointer to a met_t structure that contains the meteorological data to be written to the NetCDF file.
Note
  • The function uses the NetCDF-4 format for efficient data storage.
  • It defines the grid dimensions (time, longitude, latitude, pressure levels) and adds global attributes like units and descriptions for each variable.
  • The surface variables include surface pressure, geopotential, 2-meter temperature, and wind components, which are defined on a 2D grid (latitude × longitude).
  • The level variables, such as temperature, wind velocities, and cloud properties, are defined on a 3D grid (pressure level × latitude × longitude).
Author
Lars Hoffmann

Definition at line 14468 of file mptrac.c.

14471 {
14472
14473 /* Create file... */
14474 int ncid, varid;
14475 size_t start[4], count[4];
14476 NC(nc_create(filename, NC_NETCDF4, &ncid));
14477
14478 /* Define dimensions... */
14479 int tid, lonid, latid, levid;
14480 NC(nc_def_dim(ncid, "time", 1, &tid));
14481
14482 if (met->coord_type == 0) {
14483 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
14484 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
14485 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0,
14486 0);
14487 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0,
14488 0);
14489 } else {
14490 NC(nc_def_dim(ncid, "x", (size_t) met->nx, &lonid));
14491 NC(nc_def_dim(ncid, "y", (size_t) met->ny, &latid));
14492 NC_DEF_VAR("x", NC_DOUBLE, 1, &lonid, "x", "easting", 0, 0);
14493 NC_DEF_VAR("y", NC_DOUBLE, 1, &latid, "y", "northing", 0, 0);
14494 }
14495
14496 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
14497
14498 /* Define grid... */
14499 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
14500 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
14501 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
14502
14503 /* Define surface variables... */
14504 int dimid2[3] = { tid, latid, lonid };
14505 NC_DEF_VAR("sp", NC_FLOAT, 3, dimid2, "Surface pressure", "Pa",
14506 ctl->met_nc_level, 0);
14507 NC_DEF_VAR("z", NC_FLOAT, 3, dimid2, "Geopotential", "m**2 s**-2",
14508 ctl->met_nc_level, 0);
14509 NC_DEF_VAR("t2m", NC_FLOAT, 3, dimid2, "2 metre temperature", "K",
14510 ctl->met_nc_level, 0);
14511 NC_DEF_VAR("u10m", NC_FLOAT, 3, dimid2, "10 metre U wind component",
14512 "m s**-1", ctl->met_nc_level, 0);
14513 NC_DEF_VAR("v10m", NC_FLOAT, 3, dimid2, "10 metre V wind component",
14514 "m s**-1", ctl->met_nc_level, 0);
14515 NC_DEF_VAR("iews", NC_FLOAT, 3, dimid2,
14516 "Instantaneous eastward turbulent surface stress", "N m**-2",
14517 ctl->met_nc_level, 0);
14518 NC_DEF_VAR("inss", NC_FLOAT, 3, dimid2,
14519 "Instantaneous northward turbulent surface stress", "N m**-2",
14520 ctl->met_nc_level, 0);
14521 NC_DEF_VAR("ishf", NC_FLOAT, 3, dimid2,
14522 "Instantaneous surface sensible heat flux", "W m**-2",
14523 ctl->met_nc_level, 0);
14524 NC_DEF_VAR("lsm", NC_FLOAT, 3, dimid2, "Land/sea mask", "-",
14525 ctl->met_nc_level, 0);
14526 NC_DEF_VAR("sstk", NC_FLOAT, 3, dimid2, "Sea surface temperature", "K",
14527 ctl->met_nc_level, 0);
14528 NC_DEF_VAR("blp", NC_FLOAT, 3, dimid2, "Boundary layer pressure", "Pa",
14529 ctl->met_nc_level, 0);
14530 NC_DEF_VAR("pt", NC_FLOAT, 3, dimid2, "Tropopause pressure", "Pa",
14531 ctl->met_nc_level, 0);
14532 NC_DEF_VAR("tt", NC_FLOAT, 3, dimid2, "Tropopause temperature", "K",
14533 ctl->met_nc_level, 0);
14534 NC_DEF_VAR("zt", NC_FLOAT, 3, dimid2, "Tropopause height", "m",
14535 ctl->met_nc_level, 0);
14536 NC_DEF_VAR("h2ot", NC_FLOAT, 3, dimid2, "Tropopause water vapor", "ppv",
14537 ctl->met_nc_level, 0);
14538 NC_DEF_VAR("pct", NC_FLOAT, 3, dimid2, "Cloud top pressure", "Pa",
14539 ctl->met_nc_level, 0);
14540 NC_DEF_VAR("pcb", NC_FLOAT, 3, dimid2, "Cloud bottom pressure", "Pa",
14541 ctl->met_nc_level, 0);
14542 NC_DEF_VAR("cl", NC_FLOAT, 3, dimid2, "Total column cloud water",
14543 "kg m**2", ctl->met_nc_level, 0);
14544 NC_DEF_VAR("plcl", NC_FLOAT, 3, dimid2,
14545 "Pressure at lifted condensation level (LCL)", "Pa",
14546 ctl->met_nc_level, 0);
14547 NC_DEF_VAR("plfc", NC_FLOAT, 3, dimid2,
14548 "Pressure at level of free convection (LFC)", "Pa",
14549 ctl->met_nc_level, 0);
14550 NC_DEF_VAR("pel", NC_FLOAT, 3, dimid2,
14551 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
14552 0);
14553 NC_DEF_VAR("cape", NC_FLOAT, 3, dimid2,
14554 "Convective available potential energy", "J kg**-1",
14555 ctl->met_nc_level, 0);
14556 NC_DEF_VAR("cin", NC_FLOAT, 3, dimid2, "Convective inhibition",
14557 "J kg**-1", ctl->met_nc_level, 0);
14558 NC_DEF_VAR("o3c", NC_FLOAT, 3, dimid2, "Total column ozone", "DU",
14559 ctl->met_nc_level, 0);
14560
14561 /* Define level data... */
14562 int dimid3[4] = { tid, levid, latid, lonid };
14563 NC_DEF_VAR("t", NC_FLOAT, 4, dimid3, "Temperature", "K",
14564 ctl->met_nc_level, ctl->met_nc_quant);
14565 NC_DEF_VAR("u", NC_FLOAT, 4, dimid3, "U velocity", "m s**-1",
14566 ctl->met_nc_level, ctl->met_nc_quant);
14567 NC_DEF_VAR("v", NC_FLOAT, 4, dimid3, "V velocity", "m s**-1",
14568 ctl->met_nc_level, ctl->met_nc_quant);
14569 NC_DEF_VAR("w", NC_FLOAT, 4, dimid3, "Vertical velocity", "Pa s**-1",
14570 ctl->met_nc_level, ctl->met_nc_quant);
14571 NC_DEF_VAR("q", NC_FLOAT, 4, dimid3, "Specific humidity", "kg kg**-1",
14572 ctl->met_nc_level, ctl->met_nc_quant);
14573 NC_DEF_VAR("o3", NC_FLOAT, 4, dimid3, "Ozone mass mixing ratio",
14574 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14575 NC_DEF_VAR("clwc", NC_FLOAT, 4, dimid3, "Cloud liquid water content",
14576 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14577 NC_DEF_VAR("crwc", NC_FLOAT, 4, dimid3, "Cloud rain water content",
14578 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14579 NC_DEF_VAR("ciwc", NC_FLOAT, 4, dimid3, "Cloud ice water content",
14580 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14581 NC_DEF_VAR("cswc", NC_FLOAT, 4, dimid3, "Cloud snow water content",
14582 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14583 NC_DEF_VAR("cc", NC_FLOAT, 4, dimid3, "Cloud cover", "-",
14584 ctl->met_nc_level, ctl->met_nc_quant);
14585
14586 /* End definitions... */
14587 NC(nc_enddef(ncid));
14588
14589 /* Write grid data... */
14590 NC_PUT_DOUBLE("time", &met->time, 0);
14591
14592 if (met->coord_type == 0) {
14593 NC_PUT_DOUBLE("lon", met->lon, 0);
14594 NC_PUT_DOUBLE("lat", met->lat, 0);
14595 } else {
14596 NC_PUT_DOUBLE("x", met->lon, 0);
14597 NC_PUT_DOUBLE("y", met->lat, 0);
14598 }
14599
14600 double phelp[EP];
14601 for (int ip = 0; ip < met->np; ip++)
14602 phelp[ip] = 100. * met->p[ip];
14603 NC_PUT_DOUBLE("lev", phelp, 0);
14604
14605 /* Write surface data... */
14606 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
14607 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
14608 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
14609 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
14610 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
14611 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
14612 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
14613 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
14614 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
14615 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
14616 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
14617 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
14618 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
14619 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
14620 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
14621 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
14622 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
14623 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
14624 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
14625 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
14626 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
14627 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
14628 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
14629 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
14630
14631 /* Write level data... */
14632 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
14633 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
14634 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
14635 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
14636 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
14637 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
14638 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
14639 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
14640 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
14641 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
14642 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
14643
14644 /* Close file... */
14645 NC(nc_close(ncid));
14646}
void write_met_nc_2d(const int ncid, const char *varname, met_t *met, float var[EX][EY], const float scl)
Writes a 2D meteorological variable to a NetCDF file.
Definition: mptrac.c:14650
void write_met_nc_3d(const int ncid, const char *varname, met_t *met, float var[EX][EY][EP], const float scl)
Writes a 3D meteorological variable to a NetCDF file.
Definition: mptrac.c:14680
Here is the call graph for this function:

◆ write_met_nc_2d()

void write_met_nc_2d ( const int  ncid,
const char *  varname,
met_t met,
float  var[EX][EY],
const float  scl 
)

Writes a 2D meteorological variable to a NetCDF file.

This function writes a 2D meteorological variable, stored in the array var, to a NetCDF file with the specified variable name. The data is scaled by a factor scl before being written. The function handles memory allocation for the data copy, scaling, and freeing the allocated memory after writing the data to the NetCDF file.

Parameters
ncidThe NetCDF file ID. This is an integer that identifies the NetCDF file where the data will be written. It is assumed that this file has already been opened for writing.
varnameA pointer to a string containing the name of the variable in the NetCDF file where the data will be stored.
metA pointer to a structure of type met_t that contains metadata about the meteorological field, including the dimensions nx (number of points in x-direction) and ny (number of points in y-direction).
varA 2D array of dimensions EX x EY containing the meteorological data to be written. The data is provided in the format var[ix][iy], where ix is the index in the x-direction and iy is the index in the y-direction.
sclA scaling factor applied to each element in the var array before writing to the NetCDF file.
Author
Lars Hoffmann

Definition at line 14650 of file mptrac.c.

14655 {
14656
14657 int varid;
14658 size_t start[4], count[4];
14659
14660 /* Allocate... */
14661 float *help;
14662 ALLOC(help, float,
14663 EX * EY);
14664
14665 /* Copy data... */
14666 for (int ix = 0; ix < met->nx; ix++)
14667 for (int iy = 0; iy < met->ny; iy++)
14668 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
14669
14670 /* Write data... */
14671 LOG(2, "Write 2-D variable: %s (netCDF)", varname);
14672 NC_PUT_FLOAT(varname, help, 0);
14673
14674 /* Free... */
14675 free(help);
14676}
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1644

◆ write_met_nc_3d()

void write_met_nc_3d ( const int  ncid,
const char *  varname,
met_t met,
float  var[EX][EY][EP],
const float  scl 
)

Writes a 3D meteorological variable to a NetCDF file.

This function writes a 3D meteorological variable, stored in the array var, to a NetCDF file with the specified variable name. The data is scaled by a factor scl before being written. The function handles memory allocation for the data copy, scaling, and freeing the allocated memory after writing the data to the NetCDF file.

Parameters
ncidThe NetCDF file ID. This is an integer that identifies the NetCDF file where the data will be written. It is assumed that this file has already been opened for writing.
varnameA pointer to a string containing the name of the variable in the NetCDF file where the data will be stored.
metA pointer to a structure of type met_t that contains metadata about the meteorological field, including the dimensions nx (number of points in the x-direction), ny (number of points in the y-direction), and np (number of points in the third dimension, e.g., pressure levels).
varA 3D array of dimensions EX x EY x EP containing the meteorological data to be written. The data is provided in the format var[ix][iy][ip], where ix is the index in the x-direction, iy is the index in the y-direction, and ip is the index in the third dimension (e.g., vertical levels).
sclA scaling factor applied to each element in the var array before writing to the NetCDF file.
Author
Lars Hoffmann

Definition at line 14680 of file mptrac.c.

14685 {
14686
14687 int varid;
14688 size_t start[4], count[4];
14689
14690 /* Allocate... */
14691 float *help;
14692 ALLOC(help, float,
14693 EX * EY * EP);
14694
14695 /* Copy data... */
14696 for (int ix = 0; ix < met->nx; ix++)
14697 for (int iy = 0; iy < met->ny; iy++)
14698 for (int ip = 0; ip < met->np; ip++)
14699 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
14700
14701 /* Write data... */
14702 LOG(2, "Write 3-D variable: %s (netCDF)", varname);
14703 NC_PUT_FLOAT(varname, help, 0);
14704
14705 /* Free... */
14706 free(help);
14707}

◆ write_prof()

void write_prof ( const char *  filename,
const ctl_t ctl,
met_t met0,
met_t met1,
const atm_t atm,
const double  t 
)

Writes profile data to a specified file.

The write_prof function writes profile data to a file specified by the filename parameter. It takes control parameters (ctl), two meteorological data structures (met0 and met1), an atmospheric data structure (atm), and a time value (t) as input.

Parameters
filenameA string representing the filename where the profile data will be written.
ctlA pointer to a ctl_t structure containing control parameters.
met0A pointer to a met_t structure representing the first set of meteorological data.
met1A pointer to a met_t structure representing the second set of meteorological data.
atmA pointer to an atm_t structure representing atmospheric data.
tA double value representing the time at which the profile data is being written.

The function performs the following steps:

  • Initializes variables and allocates memory if it's the start of the simulation.
  • Reads observation data and creates a new output file if necessary.
  • Writes header information to the output file.
  • Sets grid box size and vertical coordinates.
  • Processes observations and model data within the specified time interval.
  • Calculates and writes output data for each grid cell.
  • Finalizes by closing the output file and freeing allocated memory if it's the end of the simulation.
Note
This function writes profile data to a file, including time, altitude, coordinates, atmospheric properties, observed data, and the number of observations.
Author
Lars Hoffmann

Definition at line 14711 of file mptrac.c.

14717 {
14718
14719 if (ctl->met_coord_type != 0)
14720 ERRMSG("Only lat/lon grid supported");
14721
14722 static FILE *out;
14723
14724 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
14725 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
14726
14727 static int nobs, *obscount, ip, okay;
14728
14729 /* Set timer... */
14730 SELECT_TIMER("WRITE_PROF", "OUTPUT");
14731
14732 /* Init... */
14733 if (t == ctl->t_start) {
14734
14735 /* Check quantity index for mass... */
14736 if (ctl->qnt_m < 0)
14737 ERRMSG("Need quantity mass!");
14738
14739 /* Check molar mass... */
14740 if (ctl->molmass <= 0)
14741 ERRMSG("Specify molar mass!");
14742
14743 /* Allocate... */
14744 ALLOC(lon, double,
14745 ctl->prof_nx);
14746 ALLOC(lat, double,
14747 ctl->prof_ny);
14748 ALLOC(area, double,
14749 ctl->prof_ny);
14750 ALLOC(z, double,
14751 ctl->prof_nz);
14752 ALLOC(press, double,
14753 ctl->prof_nz);
14754 ALLOC(rt, double,
14755 NOBS);
14756 ALLOC(rz, double,
14757 NOBS);
14758 ALLOC(rlon, double,
14759 NOBS);
14760 ALLOC(rlat, double,
14761 NOBS);
14762 ALLOC(robs, double,
14763 NOBS);
14764
14765 /* Read observation data... */
14766 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
14767
14768 /* Create new output file... */
14769 LOG(1, "Write profile data: %s", filename);
14770 if (!(out = fopen(filename, "w")))
14771 ERRMSG("Cannot create file!");
14772
14773 /* Write header... */
14774 fprintf(out,
14775 "# $1 = time [s]\n"
14776 "# $2 = altitude [km]\n"
14777 "# $3 = longitude [deg]\n"
14778 "# $4 = latitude [deg]\n"
14779 "# $5 = pressure [hPa]\n"
14780 "# $6 = temperature [K]\n"
14781 "# $7 = volume mixing ratio [ppv]\n"
14782 "# $8 = H2O volume mixing ratio [ppv]\n"
14783 "# $9 = O3 volume mixing ratio [ppv]\n"
14784 "# $10 = observed BT index [K]\n"
14785 "# $11 = number of observations\n");
14786
14787 /* Set grid box size... */
14788 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
14789 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
14790 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
14791
14792 /* Set vertical coordinates... */
14793 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14794 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
14795 press[iz] = P(z[iz]);
14796 }
14797
14798 /* Set horizontal coordinates... */
14799 for (int ix = 0; ix < ctl->prof_nx; ix++)
14800 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
14801 for (int iy = 0; iy < ctl->prof_ny; iy++) {
14802 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
14803 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
14804 }
14805 }
14806
14807 /* Set time interval... */
14808 const double t0 = t - 0.5 * ctl->dt_mod;
14809 const double t1 = t + 0.5 * ctl->dt_mod;
14810
14811 /* Allocate... */
14812 ALLOC(mass, double,
14813 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
14814 ALLOC(obsmean, double,
14815 ctl->prof_nx * ctl->prof_ny);
14816 ALLOC(obscount, int,
14817 ctl->prof_nx * ctl->prof_ny);
14818
14819 /* Loop over observations... */
14820 for (int i = 0; i < nobs; i++) {
14821
14822 /* Check time... */
14823 if (rt[i] < t0)
14824 continue;
14825 else if (rt[i] >= t1)
14826 break;
14827
14828 /* Check observation data... */
14829 if (!isfinite(robs[i]))
14830 continue;
14831
14832 /* Check grid boundaries and calculate indices... */
14833 if (rlon[i] < ctl->prof_lon0 || rlon[i] >= ctl->prof_lon1
14834 || rlat[i] < ctl->prof_lat0 || rlat[i] >= ctl->prof_lat1)
14835 continue;
14836 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
14837 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
14838 if (ix >= ctl->prof_nx || iy >= ctl->prof_ny)
14839 continue;
14840
14841 /* Get mean observation index... */
14842 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
14843 obsmean[idx] += robs[i];
14844 obscount[idx]++;
14845 }
14846
14847 /* Analyze model data... */
14848 for (ip = 0; ip < atm->np; ip++) {
14849
14850 /* Check time... */
14851 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14852 continue;
14853
14854 /* Check grid boundaries and get indices... */
14855 const double zpart = Z(atm->p[ip]);
14856 if (atm->lon[ip] < ctl->prof_lon0
14857 || atm->lon[ip] >= ctl->prof_lon1
14858 || atm->lat[ip] < ctl->prof_lat0
14859 || atm->lat[ip] >= ctl->prof_lat1
14860 || zpart < ctl->prof_z0 || zpart >= ctl->prof_z1)
14861 continue;
14862 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
14863 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
14864 const int iz = (int) ((zpart - ctl->prof_z0) / dz);
14865 if (ix >= ctl->prof_nx || iy >= ctl->prof_ny || iz >= ctl->prof_nz)
14866 continue;
14867
14868 /* Get total mass in grid cell... */
14869 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14870 mass[idx] += atm->q[ctl->qnt_m][ip];
14871 }
14872
14873 /* Extract profiles... */
14874 for (int ix = 0; ix < ctl->prof_nx; ix++)
14875 for (int iy = 0; iy < ctl->prof_ny; iy++) {
14876 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
14877 if (obscount[idx2] > 0) {
14878
14879 /* Check profile... */
14880 okay = 0;
14881 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14882 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14883 if (mass[idx3] > 0) {
14884 okay = 1;
14885 break;
14886 }
14887 }
14888 if (!okay)
14889 continue;
14890
14891 /* Write output... */
14892 fprintf(out, "\n");
14893
14894 /* Loop over altitudes... */
14895 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14896
14897 /* Get temperature, water vapor, and ozone... */
14899 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
14900 lon[ix], lat[iy], &temp, ci, cw, 1);
14901 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
14902 lon[ix], lat[iy], &h2o, ci, cw, 0);
14903 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
14904 lon[ix], lat[iy], &o3, ci, cw, 0);
14905
14906 /* Calculate volume mixing ratio... */
14907 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14908 vmr = MA / ctl->molmass * mass[idx3]
14909 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
14910
14911 /* Write output... */
14912 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
14913 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
14914 obsmean[idx2] / obscount[idx2], obscount[idx2]);
14915 }
14916 }
14917 }
14918
14919 /* Free... */
14920 free(mass);
14921 free(obsmean);
14922 free(obscount);
14923
14924 /* Finalize... */
14925 if (t == ctl->t_stop) {
14926
14927 /* Close output file... */
14928 fclose(out);
14929
14930 /* Free... */
14931 free(lon);
14932 free(lat);
14933 free(area);
14934 free(z);
14935 free(press);
14936 free(rt);
14937 free(rz);
14938 free(rlon);
14939 free(rlat);
14940 free(robs);
14941 }
14942}
Here is the call graph for this function:

◆ write_sample()

void write_sample ( const char *  filename,
const ctl_t ctl,
met_t met0,
met_t met1,
const atm_t atm,
const double  t 
)

Writes sample data to a specified file.

The write_sample function writes sample data to a file specified by the filename parameter. It takes control parameters (ctl), two meteorological data structures (met0 and met1), an atmospheric data structure (atm), and a time value (t) as input.

Parameters
filenameA string representing the filename where the sample data will be written.
ctlA pointer to a ctl_t structure containing control parameters.
met0A pointer to a met_t structure representing the first set of meteorological data.
met1A pointer to a met_t structure representing the second set of meteorological data.
atmA pointer to an atm_t structure representing atmospheric data.
tA double value representing the time at which the sample data is being written.

The function performs the following steps:

  • Initializes variables and allocates memory if it's the start of the simulation.
  • Reads observation data and kernel data if necessary.
  • Creates a new output file and writes header information to it.
  • Sets latitude range, squared radius, and area.
  • Processes observations and calculates sample data within the specified time interval.
  • Writes output data for each observation.
  • Finalizes by closing the output file and freeing allocated memory if it's the end of the simulation.
Note
This function writes sample data to a file, including time, altitude, coordinates, surface area, layer depth, number of particles, column density, volume mixing ratio, and observed data.
Author
Lars Hoffmann

Definition at line 14946 of file mptrac.c.

14952 {
14953
14954 if (ctl->met_coord_type != 0)
14955 ERRMSG("Only lat/lon grid supported");
14956
14957 static FILE *out;
14958
14959 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
14960 kw[EP];
14961
14962 static int nobs, nk;
14963
14964 /* Set timer... */
14965 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT");
14966
14967 /* Init... */
14968 if (t == ctl->t_start) {
14969
14970 /* Allocate... */
14971 ALLOC(rt, double,
14972 NOBS);
14973 ALLOC(rz, double,
14974 NOBS);
14975 ALLOC(rlon, double,
14976 NOBS);
14977 ALLOC(rlat, double,
14978 NOBS);
14979 ALLOC(robs, double,
14980 NOBS);
14981
14982 /* Read observation data... */
14983 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
14984
14985 /* Read kernel data... */
14986 if (ctl->sample_kernel[0] != '-')
14987 read_kernel(ctl->sample_kernel, kz, kw, &nk);
14988
14989 /* Create output file... */
14990 LOG(1, "Write sample data: %s", filename);
14991 if (!(out = fopen(filename, "w")))
14992 ERRMSG("Cannot create file!");
14993
14994 /* Write header... */
14995 fprintf(out,
14996 "# $1 = time [s]\n"
14997 "# $2 = altitude [km]\n"
14998 "# $3 = longitude [deg]\n"
14999 "# $4 = latitude [deg]\n"
15000 "# $5 = surface area [km^2]\n"
15001 "# $6 = layer depth [km]\n"
15002 "# $7 = number of particles [1]\n"
15003 "# $8 = column density [kg/m^2]\n"
15004 "# $9 = volume mixing ratio [ppv]\n"
15005 "# $10 = observed BT index [K]\n\n");
15006
15007 /* Set latitude range, squared radius, and area... */
15008 dlat = DY2DEG(ctl->sample_dx);
15009 rmax2 = SQR(ctl->sample_dx);
15010 area = M_PI * rmax2;
15011 }
15012
15013 /* Set time interval for output... */
15014 const double t0 = t - 0.5 * ctl->dt_mod;
15015 const double t1 = t + 0.5 * ctl->dt_mod;
15016
15017 /* Loop over observations... */
15018 for (int i = 0; i < nobs; i++) {
15019
15020 /* Check time... */
15021 if (rt[i] < t0)
15022 continue;
15023 else if (rt[i] >= t1)
15024 break;
15025
15026 /* Calculate Cartesian coordinates... */
15027 double x0[3];
15028 geo2cart(0, rlon[i], rlat[i], x0);
15029
15030 /* Set pressure range... */
15031 const double rp = P(rz[i]);
15032 const double ptop = P(rz[i] + ctl->sample_dz);
15033 const double pbot = P(rz[i] - ctl->sample_dz);
15034
15035 /* Init... */
15036 double mass = 0;
15037 int np = 0;
15038
15039 /* Loop over air parcels... */
15040 //#pragma omp parallel for default(shared) reduction(+:mass,np)
15041 for (int ip = 0; ip < atm->np; ip++) {
15042
15043 /* Check time... */
15044 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15045 continue;
15046
15047 /* Check latitude... */
15048 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
15049 continue;
15050
15051 /* Check horizontal distance... */
15052 double x1[3];
15053 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
15054 if (DIST2(x0, x1) > rmax2)
15055 continue;
15056
15057 /* Check pressure... */
15058 if (ctl->sample_dz > 0)
15059 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
15060 continue;
15061
15062 /* Add mass... */
15063 if (ctl->qnt_m >= 0)
15064 mass +=
15065 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
15066 np++;
15067 }
15068
15069 /* Calculate column density... */
15070 const double cd = mass / (1e6 * area);
15071
15072 /* Calculate volume mixing ratio... */
15073 double vmr = 0;
15074 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
15075 if (mass > 0) {
15076
15077 /* Get temperature... */
15078 double temp;
15080 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
15081 rlon[i], rlat[i], &temp, ci, cw, 1);
15082
15083 /* Calculate volume mixing ratio... */
15084 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
15085 }
15086 } else
15087 vmr = NAN;
15088
15089 /* Write output... */
15090 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
15091 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
15092 }
15093
15094 /* Finalize...... */
15095 if (t == ctl->t_stop) {
15096
15097 /* Close output file... */
15098 fclose(out);
15099
15100 /* Free... */
15101 free(rt);
15102 free(rz);
15103 free(rlon);
15104 free(rlat);
15105 free(robs);
15106 }
15107}
Here is the call graph for this function:

◆ write_station()

void write_station ( const char *  filename,
const ctl_t ctl,
atm_t atm,
const double  t 
)

Writes station data to a specified file.

The write_station function writes station data to a file specified by the filename parameter. It takes control parameters (ctl), an atmospheric data structure (atm), and a time value (t) as input.

Parameters
filenameA string representing the filename where the station data will be written.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure representing atmospheric data.
tA double value representing the time at which the station data is being written.

The function performs the following steps:

  • Initializes variables and opens a new file if it's the start of the simulation.
  • Writes header information to the output file.
  • Sets geolocation and search radius for station data.
  • Processes air parcels and writes station data within the specified time interval and search radius.
  • Writes station data for each air parcel satisfying the criteria.
  • Closes the output file if it's the end of the simulation.
Note
This function writes station data to a file, including time, altitude, longitude, latitude, and additional quantities specified in the control parameters.
Author
Lars Hoffmann

Definition at line 15111 of file mptrac.c.

15115 {
15116
15117 if (ctl->met_coord_type != 0)
15118 ERRMSG("Only lat/lon grid supported");
15119
15120 static FILE *out;
15121
15122 static double rmax2, x0[3], x1[3];
15123
15124 /* Set timer... */
15125 SELECT_TIMER("WRITE_STATION", "OUTPUT");
15126
15127 /* Init... */
15128 if (t == ctl->t_start) {
15129
15130 /* Write info... */
15131 LOG(1, "Write station data: %s", filename);
15132
15133 /* Create new file... */
15134 if (!(out = fopen(filename, "w")))
15135 ERRMSG("Cannot create file!");
15136
15137 /* Write header... */
15138 fprintf(out,
15139 "# $1 = time [s]\n"
15140 "# $2 = altitude [km]\n"
15141 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
15142 for (int iq = 0; iq < ctl->nq; iq++)
15143 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
15144 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
15145 fprintf(out, "\n");
15146
15147 /* Set geolocation and search radius... */
15148 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
15149 rmax2 = SQR(ctl->stat_r);
15150 }
15151
15152 /* Set time interval for output... */
15153 const double t0 = t - 0.5 * ctl->dt_mod;
15154 const double t1 = t + 0.5 * ctl->dt_mod;
15155
15156 /* Loop over air parcels... */
15157 for (int ip = 0; ip < atm->np; ip++) {
15158
15159 /* Check time... */
15160 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15161 continue;
15162
15163 /* Check time range for station output... */
15164 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
15165 continue;
15166
15167 /* Check station flag... */
15168 if (ctl->qnt_stat >= 0)
15169 if ((int) atm->q[ctl->qnt_stat][ip])
15170 continue;
15171
15172 /* Get Cartesian coordinates... */
15173 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
15174
15175 /* Check horizontal distance... */
15176 if (DIST2(x0, x1) > rmax2)
15177 continue;
15178
15179 /* Set station flag... */
15180 if (ctl->qnt_stat >= 0)
15181 atm->q[ctl->qnt_stat][ip] = 1;
15182
15183 /* Write data... */
15184 fprintf(out, "%.2f %g %g %g",
15185 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
15186 for (int iq = 0; iq < ctl->nq; iq++) {
15187 fprintf(out, " ");
15188 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
15189 }
15190 fprintf(out, "\n");
15191 }
15192
15193 /* Close file... */
15194 if (t == ctl->t_stop)
15195 fclose(out);
15196}
Here is the call graph for this function:

◆ write_vtk()

void write_vtk ( const char *  filename,
const ctl_t ctl,
const atm_t atm,
const double  t 
)

Writes VTK (Visualization Toolkit) data to a specified file.

The write_vtk function writes VTK data to a file specified by the filename parameter. It takes control parameters (ctl), an atmospheric data structure (atm), and a time value (t) as input.

Parameters
filenameA string representing the filename where the VTK data will be written.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure representing atmospheric data.
tA double value representing the time at which the VTK data is being written.

The function performs the following steps:

  • Sets a timer and logs information about writing VTK data.
  • Sets a time interval for output based on the specified time and control parameters.
  • Creates a new file and checks if the file creation was successful.
  • Counts the number of data points to be written.
  • Writes the VTK header, including metadata.
  • Writes point coordinates based on the sphere or Cartesian coordinate system.
  • Writes point data for each quantity specified in the control parameters.
  • Closes the output file.
Note
This function writes VTK data in ASCII format, including point coordinates and associated scalar data for visualization purposes.
Author
Lars Hoffmann

Definition at line 15200 of file mptrac.c.

15204 {
15205
15206 if (ctl->met_coord_type != 0)
15207 ERRMSG("Only lat/lon grid supported");
15208
15209 FILE *out;
15210
15211 /* Set timer... */
15212 SELECT_TIMER("WRITE_VTK", "OUTPUT");
15213
15214 /* Write info... */
15215 LOG(1, "Write VTK data: %s", filename);
15216
15217 /* Set time interval for output... */
15218 const double t0 = t - 0.5 * ctl->dt_mod;
15219 const double t1 = t + 0.5 * ctl->dt_mod;
15220
15221 /* Create file... */
15222 if (!(out = fopen(filename, "w")))
15223 ERRMSG("Cannot create file!");
15224
15225 /* Count data points... */
15226 int np = 0;
15227 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15228 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15229 continue;
15230 np++;
15231 }
15232
15233 /* Write header... */
15234 fprintf(out,
15235 "# vtk DataFile Version 3.0\n"
15236 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
15237
15238 /* Write point coordinates... */
15239 fprintf(out, "POINTS %d float\n", np);
15240 if (ctl->vtk_sphere) {
15241 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15242 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15243 continue;
15244 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
15245 + ctl->vtk_offset) / RE;
15246 const double coslat = cos(DEG2RAD(atm->lat[ip]));
15247 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
15248 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
15249 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
15250 fprintf(out, "%g %g %g\n", x, y, z);
15251 }
15252 } else
15253 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15254 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15255 continue;
15256 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
15257 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
15258 }
15259
15260 /* Write point data... */
15261 fprintf(out, "POINT_DATA %d\n", np);
15262 for (int iq = 0; iq < ctl->nq; iq++) {
15263 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
15264 ctl->qnt_name[iq]);
15265 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15266 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15267 continue;
15268 fprintf(out, "%g\n", atm->q[iq][ip]);
15269 }
15270 }
15271
15272 /* Close file... */
15273 fclose(out);
15274}