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...
 
double compress_speed_mib (const size_t nbytes, const double dt)
 Calculate compression throughput in MiB/s. More...
 
void compress_error_stats (const float *org, const float *cmp, const size_t n, double *mean, double *stddev, double *min, double *max, double *nrmse, double *org_mean, double *range)
 Compute error statistics between original and reconstructed data. More...
 
void compress_log_header (FILE *out)
 Write the ASCII header for per-level compression diagnostics. 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 rho, 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_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_metvar_index (const char *varname)
 Maps a meteorological variable name to its internal MPTRAC variable index. More...
 
void compress_pck (const char *varname, float *array, const size_t nxy, const size_t nz, const double *plev, const int decompress, const int pck_zstd, const int zstd_level, const int zstd_nworkers, FILE *level_log, FILE *inout)
 Compresses or decompresses a 3D array of floats. 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_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, met_t *met0, 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)
 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_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, 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, 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, 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, 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, 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, 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 read_met_nc_grid_dd_naive (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)
 Extracts and converts a timestamp from a filename to Julian seconds. More...
 
double tropo_weight (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_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 72 of file mptrac.c.

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

◆ 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 87 of file mptrac.c.

93 {
94
95 /* Set SZA threshold... */
96 const double sza_thresh = DEG2RAD(85.), csza_thresh = cos(sza_thresh);
97
98 /* Get OH data from climatology... */
99 const double oh = clim_zm(&clim->oh, t, lat, p);
100
101 /* Check beta... */
102 if (ctl->oh_chem_beta <= 0)
103 return oh;
104
105 /* Apply diurnal correction... */
106 const double csza = cos_sza(t, lon, lat);
107 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
108 return oh * exp(-ctl->oh_chem_beta / denom);
109}
double cos_sza(const double sec, const double lon, const double lat)
Calculates the cosine of the solar zenith angle.
Definition: mptrac.c:1902
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:403
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:608
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3453
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2920
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 113 of file mptrac.c.

115 {
116
117 /* Set SZA threshold... */
118 const double sza_thresh = DEG2RAD(85.), csza_thresh = cos(sza_thresh);
119
120 /* Loop over climatology data points... */
121 for (int it = 0; it < clim->oh.ntime; it++)
122 for (int iz = 0; iz < clim->oh.np; iz++)
123 for (int iy = 0; iy < clim->oh.nlat; iy++) {
124
125 /* Init... */
126 int n = 0;
127 double sum = 0;
128
129 /* Integrate day/night correction factor over longitude... */
130 for (double lon = -180; lon < 180; lon += 1.0) {
131 const double csza =
132 cos_sza(clim->oh.time[it], lon, clim->oh.lat[iy]);
133 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
134 sum += exp(-ctl->oh_chem_beta / denom);
135 n++;
136 }
137
138 /* Apply scaling factor to OH data... */
139 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
140 }
141}
double time[CT]
Time [s].
Definition: mptrac.h:3409
int np
Number of pressure levels.
Definition: mptrac.h:3406
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3418
int ntime
Number of timesteps.
Definition: mptrac.h:3400
int nlat
Number of latitudes.
Definition: mptrac.h:3403
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3412
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 145 of file mptrac.c.

150 {
151
152 /* Check pressure range... */
153 double p_help = p;
154 if (p < photo->p[photo->np - 1])
155 p_help = photo->p[photo->np - 1];
156 else if (p > photo->p[0])
157 p_help = photo->p[0];
158
159 /* Check sza range... */
160 double sza_help = sza;
161 if (sza < photo->sza[0])
162 sza_help = photo->sza[0];
163 else if (sza > photo->sza[photo->nsza - 1])
164 sza_help = photo->sza[photo->nsza - 1];
165
166 /* Check ozone column range... */
167 double o3c_help = o3c;
168 if (o3c < photo->o3c[0])
169 o3c_help = photo->o3c[0];
170 else if (o3c > photo->o3c[photo->no3c - 1])
171 o3c_help = photo->o3c[photo->no3c - 1];
172
173 /* Get indices... */
174 const int ip = locate_irr(photo->p, photo->np, p_help);
175 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
176 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
177
178 /* Interpolate photolysis rate... */
179 const double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
180 photo->p[ip + 1], rate[ip + 1][isza][io3c],
181 p_help);
182 const double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
183 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1],
184 p_help);
185 const double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
186 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c],
187 p_help);
188 const double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
189 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
190 p_help);
191 const double aux0 =
192 LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
193 const double aux1 =
194 LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
195 const double aux =
196 LIN(photo->sza[isza], aux0, photo->sza[isza + 1], aux1, sza_help);
197 return MAX(aux, 0.0);
198}
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:3481
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:3417
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1055
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1082
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3327
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3336
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3333
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3339
int np
Number of pressure levels.
Definition: mptrac.h:3324
int no3c
Number of total ozone columns.
Definition: mptrac.h:3330
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 202 of file mptrac.c.

205 {
206
207 /* Get seconds since begin of year... */
208 double sec = FMOD(t, 365.25 * 86400.);
209 while (sec < 0)
210 sec += 365.25 * 86400.;
211
212 /* Get indices... */
213 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
214 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
215
216 /* Interpolate tropopause pressure... */
217 const double p0 = LIN(clim->tropo_lat[ilat],
218 clim->tropo[isec][ilat],
219 clim->tropo_lat[ilat + 1],
220 clim->tropo[isec][ilat + 1], lat);
221 const double p1 = LIN(clim->tropo_lat[ilat],
222 clim->tropo[isec + 1][ilat],
223 clim->tropo_lat[ilat + 1],
224 clim->tropo[isec + 1][ilat + 1], lat);
225 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
226}
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:825
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3432
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3441
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3435
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3444
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3438
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 230 of file mptrac.c.

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

◆ 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 385 of file mptrac.c.

387 {
388
389 /* Interpolate... */
390 if (t <= ts->time[0])
391 return ts->vmr[0];
392 else if (t >= ts->time[ts->ntime - 1])
393 return ts->vmr[ts->ntime - 1];
394 else {
395 const int idx = locate_irr(ts->time, ts->ntime, t);
396 return LIN(ts->time[idx], ts->vmr[idx],
397 ts->time[idx + 1], ts->vmr[idx + 1], t);
398 }
399}
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3386
double time[CTS]
Time [s].
Definition: mptrac.h:3383
int ntime
Number of timesteps.
Definition: mptrac.h:3380
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 403 of file mptrac.c.

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

◆ compress_speed_mib()

double compress_speed_mib ( const size_t  nbytes,
const double  dt 
)

Calculate compression throughput in MiB/s.

This helper converts a processed byte count and elapsed wall-clock time into a throughput value expressed in MiB/s.

Parameters
[in]nbytesNumber of processed bytes.
[in]dtElapsed time in seconds.
Returns
Throughput in MiB/s, or NAN if dt is not positive.
Author
Lars Hoffmann

Definition at line 696 of file mptrac.c.

698 {
699
700 /* Calculate compression speed in MiB/s... */
701 return (dt > 0 ? ((double) nbytes) / (dt * 1024. * 1024.) : NAN);
702}

◆ compress_error_stats()

void compress_error_stats ( const float *  org,
const float *  cmp,
const size_t  n,
double *  mean,
double *  stddev,
double *  min,
double *  max,
double *  nrmse,
double *  org_mean,
double *  range 
)

Compute error statistics between original and reconstructed data.

The error is defined element-wise as cmp - org. The routine returns the mean error, standard deviation, minimum, maximum, and the normalized root-mean-square error (NRMSE), together with the mean value and value range of the original field.

Parameters
[in]orgOriginal values.
[in]cmpReconstructed/compressed values.
[in]nNumber of elements.
[out]meanMean error.
[out]stddevStandard deviation of the error.
[out]minMinimum error.
[out]maxMaximum error.
[out]nrmseNormalized root-mean-square error.
[out]org_meanMean value of the original field.
[out]rangeValue range of the original field.
Author
Lars Hoffmann

Definition at line 706 of file mptrac.c.

716 {
717
718 double avg = 0, m2 = 0, err_min = 0, err_max = 0, rmse = 0;
719 double org_min = 0, org_max = 0;
720
721 /* Calculate error statistics... */
722 for (size_t i = 0; i < n; i++) {
723 const double err = (double) cmp[i] - (double) org[i];
724 const double val = (double) org[i];
725 const double delta = err - avg;
726
727 avg += delta / ((double) i + 1.);
728 m2 += delta * (err - avg);
729 rmse += err * err;
730
731 if (i == 0 || err < err_min)
732 err_min = err;
733 if (i == 0 || err > err_max)
734 err_max = err;
735 if (i == 0 || val < org_min)
736 org_min = val;
737 if (i == 0 || val > org_max)
738 org_max = val;
739 }
740
741 *mean = avg;
742 *stddev = (n > 1 ? sqrt(m2 / ((double) n - 1.)) : 0);
743 *min = err_min;
744 *max = err_max;
745 *org_mean = 0;
746 for (size_t i = 0; i < n; i++)
747 *org_mean += (double) org[i];
748 *org_mean /= (double) n;
749 *range = org_max - org_min;
750 *nrmse = ((org_max - org_min) > 0
751 ? sqrt(rmse / (double) n) / (org_max - org_min)
752 : NAN);
753}
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:11835
Here is the call graph for this function:

◆ compress_log_header()

void compress_log_header ( FILE *  out)

Write the ASCII header for per-level compression diagnostics.

Parameters
[in,out]outOutput stream receiving the table header.
Author
Lars Hoffmann

Definition at line 757 of file mptrac.c.

758 {
759
760 /* Write file header... */
761 fprintf(out,
762 "# $1 = compression codec name [-]\n"
763 "# $2 = variable name [-]\n"
764 "# $3 = level index [-]\n"
765 "# $4 = pressure level [hPa]\n"
766 "# $5 = compression ratio [-]\n"
767 "# $6 = bits per value [bit/value]\n"
768 "# $7 = correlation coefficient [-]\n"
769 "# $8 = mean compression error [-]\n"
770 "# $9 = standard deviation of compression error [-]\n"
771 "# $10 = minimum compression error [-]\n"
772 "# $11 = maximum compression error [-]\n"
773 "# $12 = mean value of original field [-]\n"
774 "# $13 = value range of original field [-]\n"
775 "# $14 = normalized root mean square error [-]\n"
776 "# $15 = compression time [s]\n"
777 "# $16 = compression speed [MiB/s]\n"
778 "# $17 = decompression time [s]\n"
779 "# $18 = decompression speed [MiB/s]\n\n");
780}

◆ 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  rho,
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 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]rhoCorrelation coefficient, or NAN to compute it.
[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 784 of file mptrac.c.

798 {
799 static FILE *last_out = NULL;
800 static char last_var[LEN] = "";
801 double mean_err, stddev_err, min_err, max_err;
802 double nrmse, mean_org, range_org, rho_out = rho;
803
804 /* Calculate error statistics... */
805 compress_error_stats(org, cmp, n, &mean_err, &stddev_err, &min_err,
806 &max_err, &nrmse, &mean_org, &range_org);
807 if (isnan(rho_out))
808 rho_out = gsl_stats_float_correlation(org, 1, cmp, 1, n);
809
810 /* Write output... */
811 if (out != last_out) {
812 last_out = out;
813 last_var[0] = '\0';
814 }
815 if (last_var[0] != '\0' && strcmp(last_var, varname) != 0)
816 fprintf(out, "\n");
817 snprintf(last_var, LEN, "%s", varname);
818 fprintf(out,
819 "%s %s %lu %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n",
820 codec, varname, (unsigned long) lev, plev, ratio, bpv, rho_out,
821 mean_err, stddev_err, min_err, max_err, mean_org, range_org, nrmse,
822 t_comp,
823 compress_speed_mib(nbytes, t_comp), t_decomp,
824 compress_speed_mib(nbytes, t_decomp));
825}
double compress_speed_mib(const size_t nbytes, const double dt)
Calculate compression throughput in MiB/s.
Definition: mptrac.c:696
void compress_error_stats(const float *org, const float *cmp, const size_t n, double *mean, double *stddev, double *min, double *max, double *nrmse, double *org_mean, double *range)
Compute error statistics between original and reconstructed data.
Definition: mptrac.c:706
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:349
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 899 of file mptrac.c.

904 {
905
906 for (size_t iz = 0; iz < nz; iz++) {
907 off[iz] = array[iz];
908 scl[iz] = array[iz];
909 }
910
911 for (size_t ixy = 1; ixy < nxy; ixy++)
912 for (size_t iz = 0; iz < nz; iz++) {
913 const double value = array[ixy * nz + iz];
914 if (value < off[iz])
915 off[iz] = value;
916 if (value > scl[iz])
917 scl[iz] = value;
918 }
919
920 for (size_t iz = 0; iz < nz; iz++) {
921 const double range = scl[iz] - off[iz];
922 const double ref = fmax(1.0, fmax(fabs(off[iz]), fabs(scl[iz])));
923 scl[iz] = !(range > 1e-12 * ref) ? 0.0 : range;
924 }
925
926#pragma omp parallel for default(shared)
927 for (size_t ixy = 0; ixy < nxy; ixy++)
928 for (size_t iz = 0; iz < nz; iz++)
929 if (scl[iz] > 0.0)
930 array[ixy * nz + iz] =
931 (float) ((array[ixy * nz + iz] - off[iz]) / scl[iz]);
932 else
933 array[ixy * nz + iz] = 0.0f;
934}

◆ 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 938 of file mptrac.c.

943 {
944
945#pragma omp parallel for default(shared)
946 for (size_t ixy = 0; ixy < nxy; ixy++)
947 for (size_t iz = 0; iz < nz; iz++)
948 if (scl[iz] > 0.0)
949 array[ixy * nz + iz] =
950 (float) (array[ixy * nz + iz] * scl[iz] + off[iz]);
951 else
952 array[ixy * nz + iz] = (float) off[iz];
953}

◆ 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 957 of file mptrac.c.

958 {
959
960 if (strcasecmp(varname, "Z") == 0)
961 return 0;
962 if (strcasecmp(varname, "T") == 0)
963 return 1;
964 if (strcasecmp(varname, "U") == 0)
965 return 2;
966 if (strcasecmp(varname, "V") == 0)
967 return 3;
968 if (strcasecmp(varname, "W") == 0)
969 return 4;
970 if (strcasecmp(varname, "PV") == 0)
971 return 5;
972 if (strcasecmp(varname, "H2O") == 0)
973 return 6;
974 if (strcasecmp(varname, "O3") == 0)
975 return 7;
976 if (strcasecmp(varname, "LWC") == 0)
977 return 8;
978 if (strcasecmp(varname, "RWC") == 0)
979 return 9;
980 if (strcasecmp(varname, "IWC") == 0)
981 return 10;
982 if (strcasecmp(varname, "SWC") == 0)
983 return 11;
984 if (strcasecmp(varname, "CC") == 0)
985 return 12;
986
987 ERRMSG("Unknown meteorological variable name!");
988 return -1;
989}
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2110

◆ compress_pck()

void compress_pck ( const char *  varname,
float *  array,
const size_t  nxy,
const size_t  nz,
const double *  plev,
const int  decompress,
const int  pck_zstd,
const int  zstd_level,
const int  zstd_nworkers,
FILE *  level_log,
FILE *  inout 
)

Compresses or decompresses a 3D array of floats.

This function either compresses or decompresses a 3D array of floats based on the value of the decompress parameter. Compression reduces the storage size by converting float values (4 bytes) to unsigned short values (2 bytes) with scaling and offset. Decompression restores the original float values from the compressed unsigned short representation.

Parameters
varnameThe name of the variable being processed.
arrayPointer to the 3D array of floats to be compressed or decompressed.
nxyThe number of elements in the first two dimensions of the array.
nzThe number of elements in the third dimension of the array.
plevPressure levels corresponding to the third dimension of the array; used only for per-level compression diagnostics.
decompressIf non-zero, the function will decompress the data; otherwise, it will compress the data.
pck_zstdIf non-zero, an additional ZSTD compression layer is applied to or expected around the packed PCK payload.
zstd_levelZSTD compression level used when pck_zstd is enabled.
zstd_nworkersZSTD worker thread count used when pck_zstd is enabled.
level_logOptional file stream for per-level compression diagnostics, or NULL to disable logging.
inoutFile pointer for input or output operations. It is used for reading compressed data during decompression and writing compressed data during compression.

The function performs the following steps:

  • If decompressing:
    • Reads scaling factors, offsets, and compressed data from the file.
    • Decompresses the data and stores it in the array.
  • If compressing:
    • Computes the minimum and maximum values for each slice in the third dimension.
    • Calculates scaling factors and offsets based on these values.
    • Compresses the data by converting floats to unsigned shorts using the scaling factors and offsets.
    • Optionally applies an additional ZSTD compression step to the packed PCK payload.
    • Writes the scaling factors, offsets, and compressed data to the file.

The function allocates memory for the compressed data array and frees it before returning.

Author
Lars Hoffmann

Definition at line 993 of file mptrac.c.

1004 {
1005
1006#ifndef ZSTD
1007 (void) zstd_level;
1008 (void) zstd_nworkers;
1009#endif
1010
1011 double vmin[EP], vmax[EP], off[EP], scl[EP];
1012 unsigned short *sarray;
1013 const size_t payload_len = 2 * nz * sizeof(double)
1014 + nxy * nz * sizeof(unsigned short);
1015 size_t stored_len = payload_len;
1016
1017 /* Allocate... */
1018 ALLOC(sarray, unsigned short,
1019 nxy * nz);
1020
1021 /* Read compressed stream and decompress array... */
1022 if (decompress) {
1023 double t_zstd = 0.0;
1024
1025 /* Read data... */
1026 if (pck_zstd) {
1027#ifdef ZSTD
1028 uint64_t magic;
1029 unsigned char *compr = NULL, *payload = NULL;
1030
1031 FREAD(&magic, uint64_t, 1, inout);
1032 if (magic != pck_zstd_magic)
1033 ERRMSG("PCK+ZSTD magic mismatch! Check MET_PCK_ZSTD and file type.");
1034 FREAD(&stored_len, size_t,
1035 1,
1036 inout);
1037 ALLOC(compr, unsigned char,
1038 stored_len);
1039 FREAD(compr, unsigned char,
1040 stored_len,
1041 inout);
1042 ALLOC(payload, unsigned char,
1043 payload_len);
1044 decompress_zstd_buffer(compr, stored_len, payload, payload_len,
1045 &t_zstd);
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),
1049 nxy * nz * sizeof(unsigned short));
1050 free(payload);
1051 free(compr);
1052#else
1053 ERRMSG("MPTRAC was compiled without ZSTD compression!");
1054#endif
1055 } else {
1056 FREAD(&scl, double,
1057 nz,
1058 inout);
1059 FREAD(&off, double,
1060 nz,
1061 inout);
1062 FREAD(sarray, unsigned short,
1063 nxy * nz,
1064 inout);
1065 }
1066
1067 /* Measure time... */
1068 const double t0 = omp_get_wtime();
1069
1070 /* Convert to float... */
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 /* Write info... */
1078 const double t_decomp = t_zstd + omp_get_wtime() - t0;
1079 const double ratio_out =
1080 (double) (nxy * nz * sizeof(float)) / (double) stored_len;
1081 const double bpv_out = (8. * (double) stored_len) / (double) (nxy * nz);
1082 LOG(2, "Read 3-D variable: %s"
1083 " (PCK%s, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1084 varname, pck_zstd ? "+ZSTD" : "", ratio_out, bpv_out, t_decomp,
1085 compress_speed_mib(nxy * nz * sizeof(float), 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 rho[EP], mean[EP], stddev[EP], min[EP], max[EP], nrmse[EP];
1093 double org_mean[EP], range[EP];
1094
1095 /* Allocate... */
1096 ALLOC(tmp_org, float,
1097 nxy);
1098 ALLOC(tmp_pck, float,
1099 nxy);
1100
1101 /* Get range... */
1102 for (size_t iz = 0; iz < nz; iz++) {
1103 vmin[iz] = array[iz];
1104 vmax[iz] = array[iz];
1105 }
1106 for (size_t ixy = 1; ixy < nxy; ixy++)
1107 for (size_t iz = 0; iz < nz; iz++) {
1108 if (array[ixy * nz + iz] < vmin[iz])
1109 vmin[iz] = array[ixy * nz + iz];
1110 if (array[ixy * nz + iz] > vmax[iz])
1111 vmax[iz] = array[ixy * nz + iz];
1112 }
1113
1114 /* Get offset and scaling factor... */
1115 for (size_t iz = 0; iz < nz; iz++) {
1116 scl[iz] = (vmax[iz] - vmin[iz]) / 65533.;
1117 off[iz] = vmin[iz];
1118 }
1119
1120 /* Convert to short and evaluate per level... */
1121 for (size_t iz = 0; iz < nz; iz++) {
1122 const double t0 = omp_get_wtime();
1123
1124#pragma omp parallel for default(shared)
1125 for (size_t ixy = 0; ixy < nxy; ixy++)
1126 if (scl[iz] != 0)
1127 sarray[ixy * nz + iz] =
1128 (unsigned short) ((array[ixy * nz + iz] - off[iz]) / scl[iz] +
1129 .5);
1130 else
1131 sarray[ixy * nz + iz] = 0;
1132
1133 const double t_comp = omp_get_wtime() - t0;
1134 t_comp_sum += t_comp;
1135
1136 const double t1 = omp_get_wtime();
1137
1138#pragma omp parallel for default(shared)
1139 for (size_t ixy = 0; ixy < nxy; ixy++) {
1140 tmp_org[ixy] = array[ixy * nz + iz];
1141 tmp_pck[ixy] = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1142 }
1143
1144 const double t_decomp = omp_get_wtime() - t1;
1145 t_decomp_sum += t_decomp;
1146
1147 if (level_log) {
1148 compress_error_stats(tmp_org, tmp_pck, nxy, &mean[iz], &stddev[iz],
1149 &min[iz], &max[iz], &nrmse[iz], &org_mean[iz],
1150 &range[iz]);
1151 rho[iz] = gsl_stats_float_correlation(tmp_org, 1, tmp_pck, 1, nxy);
1152 }
1153 }
1154
1155 /* Write data... */
1156 void *stored_data = NULL;
1157
1158 if (pck_zstd) {
1159#ifdef ZSTD
1160 unsigned char *payload = NULL, *payload_chk = NULL;
1161 ALLOC(payload, unsigned char,
1162 payload_len);
1163 memcpy(payload, scl, nz * sizeof(double));
1164 memcpy(payload + nz * sizeof(double), off, nz * sizeof(double));
1165 memcpy(payload + 2 * nz * sizeof(double), sarray,
1166 nxy * nz * sizeof(unsigned short));
1167 stored_len = compress_zstd_buffer(payload, payload_len, zstd_level,
1168 zstd_nworkers, &stored_data, &t_zstd);
1169 ALLOC(payload_chk, unsigned char,
1170 payload_len);
1171 decompress_zstd_buffer(stored_data, stored_len, payload_chk,
1172 payload_len, &t_zstd_decomp);
1173 free(payload_chk);
1174 free(payload);
1175 FWRITE(&pck_zstd_magic, uint64_t, 1, inout);
1176 FWRITE(&stored_len, size_t,
1177 1,
1178 inout);
1179 FWRITE(stored_data, unsigned char,
1180 stored_len,
1181 inout);
1182#else
1183 ERRMSG("MPTRAC was compiled without ZSTD compression!");
1184#endif
1185 } else {
1186 FWRITE(&scl, double,
1187 nz,
1188 inout);
1189 FWRITE(&off, double,
1190 nz,
1191 inout);
1192 FWRITE(sarray, unsigned short,
1193 nxy * nz,
1194 inout);
1195 }
1196
1197 /* Write info... */
1198 const double ratio_out =
1199 (double) (nxy * nz * sizeof(float)) / (double) stored_len;
1200 const double bpv_out = (8. * (double) stored_len) / (double) (nxy * nz);
1201 const double t_comp = t_comp_sum + t_zstd;
1202 const double t_decomp = t_decomp_sum + t_zstd_decomp;
1203 LOG(2, "Write 3-D variable: %s"
1204 " (PCK%s, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1205 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1206 varname, pck_zstd ? "+ZSTD" : "", ratio_out, bpv_out, t_comp,
1207 compress_speed_mib(nxy * nz * sizeof(float), t_comp),
1208 t_decomp, compress_speed_mib(nxy * nz * sizeof(float), t_decomp));
1209
1210 /* Write per-level diagnostics... */
1211 if (level_log) {
1212 const double ratio_level = ratio_out;
1213 const double bpv_level = bpv_out;
1214 const double t_comp_level = t_comp / (double) nz;
1215 const double t_decomp_level = t_decomp / (double) nz;
1216 for (size_t iz = 0; iz < nz; iz++)
1217 fprintf(level_log,
1218 "%s %s %lu %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n",
1219 pck_zstd ? "PCKZSTD" : "PCK", varname, (unsigned long) iz,
1220 plev[iz], ratio_level, bpv_level,
1221 rho[iz], mean[iz], stddev[iz], min[iz], max[iz], org_mean[iz],
1222 range[iz], nrmse[iz],
1223 t_comp_level,
1224 compress_speed_mib(nxy * sizeof(float), t_comp_level),
1225 t_decomp_level,
1226 compress_speed_mib(nxy * sizeof(float), t_decomp_level));
1227 }
1228
1229 /* Free... */
1230 free(stored_data);
1231 free(tmp_org);
1232 free(tmp_pck);
1233 }
1234
1235 /* Free... */
1236 free(sarray);
1237}
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:863
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:843
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:457
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:334
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 1902 of file mptrac.c.

1905 {
1906
1907 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
1908 const double D = sec / 86400 - 0.5;
1909
1910 /* Geocentric apparent ecliptic longitude [rad]... */
1911 const double g = DEG2RAD(357.529 + 0.98560028 * D);
1912 const double q = 280.459 + 0.98564736 * D;
1913 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
1914
1915 /* Mean obliquity of the ecliptic [rad]... */
1916 const double e = DEG2RAD(23.439 - 0.00000036 * D);
1917
1918 /* Declination [rad]... */
1919 const double sindec = sin(e) * sin(L);
1920
1921 /* Right ascension [rad]... */
1922 const double ra = atan2(cos(e) * sin(L), cos(L));
1923
1924 /* Greenwich Mean Sidereal Time [h]... */
1925 const double GMST = 18.697374558 + 24.06570982441908 * D;
1926
1927 /* Local Sidereal Time [h]... */
1928 const double LST = GMST + lon / 15;
1929
1930 /* Hour angle [rad]... */
1931 const double h = LST / 12 * M_PI - ra;
1932
1933 /* Convert latitude... */
1934 const double lat_help = DEG2RAD(lat);
1935
1936 /* Return cosine of solar zenith angle... */
1937 return sin(lat_help) * sindec + cos(lat_help) * sqrt(1 -
1938 SQR(sindec)) * cos(h);
1939}
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1741

◆ 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 1943 of file mptrac.c.

1947 {
1948
1949 const int
1950 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1951 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1952
1953 /* Get day of year... */
1954 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
1955 *doy = d0l[mon - 1] + day - 1;
1956 else
1957 *doy = d0[mon - 1] + day - 1;
1958}

◆ 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 2496 of file mptrac.c.

2500 {
2501
2502 const int
2503 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
2504 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
2505
2506 int i;
2507
2508 /* Get month and day... */
2509 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
2510 for (i = 11; i > 0; i--)
2511 if (d0l[i] <= doy)
2512 break;
2513 *mon = i + 1;
2514 *day = doy - d0l[i] + 1;
2515 } else {
2516 for (i = 11; i > 0; i--)
2517 if (d0[i] <= doy)
2518 break;
2519 *mon = i + 1;
2520 *day = doy - d0[i] + 1;
2521 }
2522}

◆ 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 2526 of file mptrac.c.

2529 {
2530
2531 double data[2 * EX];
2532
2533 /* Check size... */
2534 if (n > EX)
2535 ERRMSG("Too many data points!");
2536
2537 /* Allocate... */
2538 gsl_fft_complex_wavetable *wavetable =
2539 gsl_fft_complex_wavetable_alloc((size_t) n);
2540 gsl_fft_complex_workspace *workspace =
2541 gsl_fft_complex_workspace_alloc((size_t) n);
2542
2543 /* Set data (real, complex)... */
2544 for (int i = 0; i < n; i++) {
2545 data[2 * i] = fcReal[i];
2546 data[2 * i + 1] = fcImag[i];
2547 }
2548
2549 /* Calculate FFT... */
2550 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
2551
2552 /* Copy data... */
2553 for (int i = 0; i < n; i++) {
2554 fcReal[i] = data[2 * i];
2555 fcImag[i] = data[2 * i + 1];
2556 }
2557
2558 /* Free... */
2559 gsl_fft_complex_wavetable_free(wavetable);
2560 gsl_fft_complex_workspace_free(workspace);
2561}
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:339

◆ 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 2565 of file mptrac.c.

2569 {
2570
2571 const double radius = z + RE;
2572 const double latrad = DEG2RAD(lat);
2573 const double lonrad = DEG2RAD(lon);
2574 const double coslat = cos(latrad);
2575
2576 x[0] = radius * coslat * cos(lonrad);
2577 x[1] = radius * coslat * sin(lonrad);
2578 x[2] = radius * sin(latrad);
2579}

◆ 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 2583 of file mptrac.c.

2589 {
2590
2591 char repl[LEN];
2592
2593 double t6, r;
2594
2595 int year, mon, day, hour, min, sec;
2596
2597 /* Round time to fixed intervals... */
2598 if (direct == -1)
2599 t6 = floor(t / dt_met) * dt_met;
2600 else
2601 t6 = ceil(t / dt_met) * dt_met;
2602
2603 /* Decode time... */
2604 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
2605
2606 /* Set filename of MPTRAC meteo files... */
2607 if (ctl->met_clams == 0) {
2608 if (ctl->met_type == 0)
2609 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
2610 else if (ctl->met_type == 1)
2611 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
2612 else if (ctl->met_type == 2)
2613 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
2614 else if (ctl->met_type == 3)
2615 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
2616 else if (ctl->met_type == 4)
2617 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
2618 else if (ctl->met_type == 5)
2619 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
2620 else if (ctl->met_type == 7)
2621 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
2622 else if (ctl->met_type == 8)
2623 sprintf(filename, "%s_YYYY_MM_DD_HH.lz4", metbase);
2624 sprintf(repl, "%d", year);
2625 get_met_replace(filename, "YYYY", repl);
2626 sprintf(repl, "%02d", mon);
2627 get_met_replace(filename, "MM", repl);
2628 sprintf(repl, "%02d", day);
2629 get_met_replace(filename, "DD", repl);
2630 sprintf(repl, "%02d", hour);
2631 get_met_replace(filename, "HH", repl);
2632 }
2633
2634 /* Set filename of CLaMS meteo files... */
2635 else {
2636 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
2637 sprintf(repl, "%d", year);
2638 get_met_replace(filename, "YYYY", repl);
2639 sprintf(repl, "%02d", year % 100);
2640 get_met_replace(filename, "YY", repl);
2641 sprintf(repl, "%02d", mon);
2642 get_met_replace(filename, "MM", repl);
2643 sprintf(repl, "%02d", day);
2644 get_met_replace(filename, "DD", repl);
2645 sprintf(repl, "%02d", hour);
2646 get_met_replace(filename, "HH", repl);
2647 }
2648}
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:3187
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:2652
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2559
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:2556
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 repace 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 2652 of file mptrac.c.

2655 {
2656
2657 char buffer[LEN];
2658
2659 /* Iterate... */
2660 for (int i = 0; i < 3; i++) {
2661
2662 /* Replace sub-string... */
2663 char *ch;
2664 if (!(ch = strstr(orig, search)))
2665 return;
2666 strncpy(buffer, orig, (size_t) (ch - orig));
2667 buffer[ch - orig] = 0;
2668 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
2669 orig[0] = 0;
2670 strcpy(orig, buffer);
2671 }
2672}

◆ 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 2676 of file mptrac.c.

2691 {
2692
2694
2695 ctl->met_tropo = met_tropo;
2696 read_met_tropo(ctl, clim, met);
2697#pragma omp parallel for default(shared) private(ci,cw)
2698 for (int ix = 0; ix < nx; ix++)
2699 for (int iy = 0; iy < ny; iy++) {
2700 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2701 &pt[iy * nx + ix], ci, cw, 1);
2702 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2703 &ps[iy * nx + ix], ci, cw, 0);
2704 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2705 &zs[iy * nx + ix], ci, cw, 0);
2706 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2707 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2708 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2709 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2710 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2711 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2712 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2713 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2714 }
2715}
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:2976
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:11410
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:2918
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:878
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2680
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3617
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3527
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3533
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3620
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3602
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3560
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3599
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 2719 of file mptrac.c.

2727 {
2728
2729 /* Check longitude... */
2730 *lon2 = FMOD(lon, 360.);
2731 if (*lon2 < lons[0])
2732 *lon2 += 360;
2733 else if (*lon2 > lons[nlon - 1])
2734 *lon2 -= 360;
2735
2736 /* Check latitude... */
2737 *lat2 = lat;
2738 if (lats[0] < lats[nlat - 1])
2739 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
2740 else
2741 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
2742}

◆ 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 2746 of file mptrac.c.

2760 {
2761
2762 if (init) {
2763
2764 /* Check longitude and latitude... */
2765 double lon2, lat2;
2766 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
2767 &lon2, &lat2);
2768
2769 /* Get horizontal indizes... */
2770 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
2771 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
2772
2773 /* Locate the vertical indizes for each edge of the column... */
2774 int ind[2][4];
2775 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
2776 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
2777
2778 /* Find minimum and maximum indizes... */
2779 ci[2] = ind[0][0];
2780 int k_max = ind[0][0];
2781 for (int i = 0; i < 2; i++)
2782 for (int j = 0; j < 4; j++) {
2783 if (ci[2] > ind[i][j])
2784 ci[2] = ind[i][j];
2785 if (k_max < ind[i][j])
2786 k_max = ind[i][j];
2787 }
2788
2789 /* Get weighting factors for time, longitude and latitude... */
2790 cw[3] = (ts - met0->time) / (met1->time - met0->time);
2791 cw[0] = (lon2 - met0->lon[ci[0]]) /
2792 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
2793 cw[1] = (lat2 - met0->lat[ci[1]]) /
2794 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
2795
2796 /* Interpolate in time at the lowest level... */
2797 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
2798 - heights0[ci[0]][ci[1]][ci[2]])
2799 + heights0[ci[0]][ci[1]][ci[2]];
2800 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
2801 - heights0[ci[0]][ci[1] + 1][ci[2]])
2802 + heights0[ci[0]][ci[1] + 1][ci[2]];
2803 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
2804 - heights0[ci[0] + 1][ci[1]][ci[2]])
2805 + heights0[ci[0] + 1][ci[1]][ci[2]];
2806 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
2807 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
2808 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
2809
2810 /* Interpolate in latitude direction... */
2811 double height0 = cw[1] * (height01 - height00) + height00;
2812 double height1 = cw[1] * (height11 - height10) + height10;
2813
2814 /* Interpolate in longitude direction... */
2815 double height_bot = cw[0] * (height1 - height0) + height0;
2816
2817 /* Interpolate in time at the upper level... */
2818 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2819 - heights0[ci[0]][ci[1]][ci[2] + 1])
2820 + heights0[ci[0]][ci[1]][ci[2] + 1];
2821 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2822 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2823 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2824 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2825 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2826 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2827 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2828 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2829 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2830
2831 /* Interpolate in latitude direction... */
2832 height0 = cw[1] * (height01 - height00) + height00;
2833 height1 = cw[1] * (height11 - height10) + height10;
2834
2835 /* Interpolate in longitude direction... */
2836 double height_top = cw[0] * (height1 - height0) + height0;
2837
2838 /* Search at higher levels if height is not in box... */
2839 while (((heights0[0][0][0] > heights0[0][0][1]) &&
2840 ((height_bot <= height) || (height_top > height))
2841 && (height_bot >= height) && (ci[2] < k_max))
2842 ||
2843 ((heights0[0][0][0] < heights0[0][0][1]) &&
2844 ((height_bot >= height) || (height_top < height))
2845 && (height_bot <= height) && (ci[2] < k_max))
2846 ) {
2847
2848 ci[2]++;
2849 height_bot = height_top;
2850
2851 /* Interpolate in time at the next level... */
2852 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2853 - heights0[ci[0]][ci[1]][ci[2] + 1])
2854 + heights0[ci[0]][ci[1]][ci[2] + 1];
2855 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2856 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2857 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2858 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2859 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2860 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2861 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2862 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2863 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2864
2865 /* Interpolate in latitude direction... */
2866 height0 = cw[1] * (height01 - height00) + height00;
2867 height1 = cw[1] * (height11 - height10) + height10;
2868
2869 /* Interpolate in longitude direction... */
2870 height_top = cw[0] * (height1 - height0) + height0;
2871 }
2872
2873 /* Get vertical weighting factors... */
2874 cw[2] = (height - height_bot)
2875 / (height_top - height_bot);
2876 }
2877
2878 /* Calculate the needed array values... */
2879 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
2880 - array0[ci[0]][ci[1]][ci[2]])
2881 + array0[ci[0]][ci[1]][ci[2]];
2882 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
2883 - array0[ci[0] + 1][ci[1]][ci[2]])
2884 + array0[ci[0] + 1][ci[1]][ci[2]];
2885 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
2886 - array0[ci[0]][ci[1] + 1][ci[2]])
2887 + array0[ci[0]][ci[1] + 1][ci[2]];
2888 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
2889 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
2890 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
2891 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
2892 - array0[ci[0]][ci[1]][ci[2] + 1])
2893 + array0[ci[0]][ci[1]][ci[2] + 1];
2894 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2895 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2896 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2897 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2898 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2899 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2900 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2901 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2902 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2903
2904 const double array00 = cw[0] * (array100 - array000) + array000;
2905 const double array10 = cw[0] * (array110 - array010) + array010;
2906 const double array01 = cw[0] * (array101 - array001) + array001;
2907 const double array11 = cw[0] * (array111 - array011) + array011;
2908
2909 const double aux0 = cw[1] * (array10 - array00) + array00;
2910 const double aux1 = cw[1] * (array11 - array01) + array01;
2911
2912 /* Interpolate vertically... */
2913 *var = cw[2] * (aux1 - aux0) + aux0;
2914}
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:3500
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:2719
int nx
Number of longitudes.
Definition: mptrac.h:3494
int ny
Number of latitudes.
Definition: mptrac.h:3497
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3506
int npl
Number of model levels.
Definition: mptrac.h:3503
double time
Time [s].
Definition: mptrac.h:3491
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3509
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 2918 of file mptrac.c.

2927 {
2928
2929 /* Initialize interpolation... */
2930 if (init) {
2931
2932 /* Check longitude and latitude... */
2933 double lon2, lat2;
2934 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2935 &lon2, &lat2);
2936
2937 /* Get interpolation indices... */
2938 ci[0] = locate_irr(met->p, met->np, p);
2939 ci[1] = locate_reg(met->lon, met->nx, lon2);
2940 ci[2] = locate_irr(met->lat, met->ny, lat2);
2941
2942 /* Get interpolation weights... */
2943 cw[0] = (met->p[ci[0] + 1] - p)
2944 / (met->p[ci[0] + 1] - met->p[ci[0]]);
2945 cw[1] = (met->lon[ci[1] + 1] - lon2)
2946 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2947 cw[2] = (met->lat[ci[2] + 1] - lat2)
2948 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2949 }
2950
2951 /* Interpolate vertically... */
2952 const double aux00 =
2953 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
2954 + array[ci[1]][ci[2]][ci[0] + 1];
2955 const double aux01 =
2956 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
2957 array[ci[1]][ci[2] + 1][ci[0] + 1])
2958 + array[ci[1]][ci[2] + 1][ci[0] + 1];
2959 const double aux10 =
2960 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
2961 array[ci[1] + 1][ci[2]][ci[0] + 1])
2962 + array[ci[1] + 1][ci[2]][ci[0] + 1];
2963 const double aux11 =
2964 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
2965 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
2966 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
2967
2968 /* Interpolate horizontally... */
2969 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2970 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2971 *var = cw[1] * (aux0 - aux1) + aux1;
2972}
int np
Number of pressure levels.
Definition: mptrac.h:3500
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3512
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 2976 of file mptrac.c.

2984 {
2985
2986 /* Initialize interpolation... */
2987 if (init) {
2988
2989 /* Check longitude and latitude... */
2990 double lon2, lat2;
2991 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2992 &lon2, &lat2);
2993
2994 /* Get interpolation indices... */
2995 ci[1] = locate_reg(met->lon, met->nx, lon2);
2996 ci[2] = locate_irr(met->lat, met->ny, lat2);
2997
2998 /* Get interpolation weights... */
2999 cw[1] = (met->lon[ci[1] + 1] - lon2)
3000 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
3001 cw[2] = (met->lat[ci[2] + 1] - lat2)
3002 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
3003 }
3004
3005 /* Set variables... */
3006 const double aux00 = array[ci[1]][ci[2]];
3007 const double aux01 = array[ci[1]][ci[2] + 1];
3008 const double aux10 = array[ci[1] + 1][ci[2]];
3009 const double aux11 = array[ci[1] + 1][ci[2] + 1];
3010
3011 /* Interpolate horizontally... */
3012 if (isfinite(aux00) && isfinite(aux01)
3013 && isfinite(aux10) && isfinite(aux11)) {
3014 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
3015 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
3016 *var = cw[1] * (aux0 - aux1) + aux1;
3017 } else {
3018 if (cw[2] < 0.5) {
3019 if (cw[1] < 0.5)
3020 *var = aux11;
3021 else
3022 *var = aux01;
3023 } else {
3024 if (cw[1] < 0.5)
3025 *var = aux10;
3026 else
3027 *var = aux00;
3028 }
3029 }
3030}
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 3034 of file mptrac.c.

3046 {
3047
3048 double var0, var1;
3049
3050 /* Spatial interpolation... */
3051 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
3052 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
3053
3054 /* Get weighting factor... */
3055 const double wt = (met1->time - ts) / (met1->time - met0->time);
3056
3057 /* Interpolate... */
3058 *var = wt * (var0 - var1) + var1;
3059}
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 3063 of file mptrac.c.

3074 {
3075
3076 double var0, var1;
3077
3078 /* Spatial interpolation... */
3079 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
3080 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
3081
3082 /* Get weighting factor... */
3083 const double wt = (met1->time - ts) / (met1->time - met0->time);
3084
3085 /* Interpolate... */
3086 if (isfinite(var0) && isfinite(var1))
3087 *var = wt * (var0 - var1) + var1;
3088 else if (wt < 0.5)
3089 *var = var1;
3090 else
3091 *var = var0;
3092}
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 3096 of file mptrac.c.

3110 {
3111
3112 double mean = 0;
3113
3114 int n = 0;
3115
3116 /* Check longitude and latitude... */
3117 double lon2, lat2;
3118 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
3119
3120 /* Get indices... */
3121 const int ix = locate_reg(lons, (int) nlon, lon2);
3122 const int iy = locate_irr(lats, (int) nlat, lat2);
3123
3124 /* Calculate standard deviation... */
3125 *sigma = 0;
3126 for (int dx = 0; dx < 2; dx++)
3127 for (int dy = 0; dy < 2; dy++) {
3128 if (isfinite(array0[ix + dx][iy + dy])) {
3129 mean += array0[ix + dx][iy + dy];
3130 *sigma += SQR(array0[ix + dx][iy + dy]);
3131 n++;
3132 }
3133 if (isfinite(array1[ix + dx][iy + dy])) {
3134 mean += array1[ix + dx][iy + dy];
3135 *sigma += SQR(array1[ix + dx][iy + dy]);
3136 n++;
3137 }
3138 }
3139 if (n > 0)
3140 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
3141
3142 /* Linear interpolation... */
3143 if (method == 1 && isfinite(array0[ix][iy])
3144 && isfinite(array0[ix][iy + 1])
3145 && isfinite(array0[ix + 1][iy])
3146 && isfinite(array0[ix + 1][iy + 1])
3147 && isfinite(array1[ix][iy])
3148 && isfinite(array1[ix][iy + 1])
3149 && isfinite(array1[ix + 1][iy])
3150 && isfinite(array1[ix + 1][iy + 1])) {
3151
3152 const double aux00 = LIN(lons[ix], array0[ix][iy],
3153 lons[ix + 1], array0[ix + 1][iy], lon2);
3154 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
3155 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
3156 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
3157
3158 const double aux10 = LIN(lons[ix], array1[ix][iy],
3159 lons[ix + 1], array1[ix + 1][iy], lon2);
3160 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
3161 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
3162 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
3163
3164 *var = LIN(time0, aux0, time1, aux1, time);
3165 }
3166
3167 /* Nearest neighbor interpolation... */
3168 else {
3169 const double aux00 = NN(lons[ix], array0[ix][iy],
3170 lons[ix + 1], array0[ix + 1][iy], lon2);
3171 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
3172 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
3173 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
3174
3175 const double aux10 = NN(lons[ix], array1[ix][iy],
3176 lons[ix + 1], array1[ix + 1][iy], lon2);
3177 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
3178 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
3179 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
3180
3181 *var = NN(time0, aux0, time1, aux1, time);
3182 }
3183}
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1431
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 3187 of file mptrac.c.

3195 {
3196
3197 struct tm t0, *t1;
3198
3199 t0.tm_year = 100;
3200 t0.tm_mon = 0;
3201 t0.tm_mday = 1;
3202 t0.tm_hour = 0;
3203 t0.tm_min = 0;
3204 t0.tm_sec = 0;
3205
3206 const time_t jsec0 = (time_t) jsec + timegm(&t0);
3207 t1 = gmtime(&jsec0);
3208
3209 *year = t1->tm_year + 1900;
3210 *mon = t1->tm_mon + 1;
3211 *day = t1->tm_mday;
3212 *hour = t1->tm_hour;
3213 *min = t1->tm_min;
3214 *sec = t1->tm_sec;
3215 *remain = jsec - floor(jsec);
3216}

◆ 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 3220 of file mptrac.c.

3224 {
3225
3226 /* Check number of data points... */
3227 if (nk < 2)
3228 return 1.0;
3229
3230 /* Get altitude... */
3231 const double z = Z(p);
3232
3233 /* Get weighting factor... */
3234 if (z < kz[0])
3235 return kw[0];
3236 else if (z > kz[nk - 1])
3237 return kw[nk - 1];
3238 else {
3239 const int idx = locate_irr(kz, nk, z);
3240 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
3241 }
3242}
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 3246 of file mptrac.c.

3248 {
3249
3250 /*
3251 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
3252 and water vapor volume mixing ratio [1].
3253
3254 Reference: https://en.wikipedia.org/wiki/Lapse_rate
3255 */
3256
3257 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
3258
3259 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
3260}
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:310
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1728
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:275
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:265
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:260
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:255

◆ 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 3264 of file mptrac.c.

3265 {
3266
3267 if (0 == ctl->met_press_level_def) {
3268
3269 ERRMSG
3270 ("MET_PRESS_LEVEL_DEF=0 is disabled. Use 3 for the extended L137 set.");
3271
3272 } else if (1 == ctl->met_press_level_def) {
3273
3274 ERRMSG
3275 ("MET_PRESS_LEVEL_DEF=1 is disabled. Use 4 for the extended L91 set.");
3276
3277 } else if (2 == ctl->met_press_level_def) {
3278
3279 ERRMSG
3280 ("MET_PRESS_LEVEL_DEF=2 is disabled. Use 5 for the extended L60 set.");
3281
3282 } else if (3 == ctl->met_press_level_def) {
3283
3284 ctl->met_np = 147;
3285
3286 const double press[147] = {
3287 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
3288 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
3289 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
3290 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
3291 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
3292 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
3293 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
3294 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
3295 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
3296 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
3297 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
3298 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
3299 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
3300 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
3301 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
3302 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
3303 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
3304 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
3305 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
3306 1031.97,
3307 1035.09, 1038.21, 1041.33, 1044.45
3308 };
3309
3310 for (int ip = 0; ip < ctl->met_np; ip++)
3311 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3312
3313 } else if (4 == ctl->met_press_level_def) {
3314
3315 ctl->met_np = 101;
3316
3317 const double press[101] = {
3318 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
3319 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
3320 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
3321 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
3322 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
3323 113.6382,
3324 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
3325 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
3326 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
3327 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
3328 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
3329 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
3330 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
3331 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
3332 1028.85, 1031.97,
3333 1035.09, 1038.21, 1041.33, 1044.45
3334 };
3335
3336 for (int ip = 0; ip < ctl->met_np; ip++)
3337 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3338
3339 } else if (5 == ctl->met_press_level_def) {
3340
3341 ctl->met_np = 62;
3342
3343 const double press[62] = {
3344 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
3345 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
3346 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
3347 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
3348 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
3349 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
3350 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
3351 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
3352 1044.45
3353 };
3354
3355 for (int ip = 0; ip < ctl->met_np; ip++)
3356 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3357
3358 } else if (6 == ctl->met_press_level_def) {
3359
3360 ctl->met_np = 137;
3361
3362 const double press[137] = {
3363 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
3364 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
3365 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
3366 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
3367 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
3368 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
3369 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
3370 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
3371 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
3372 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
3373 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
3374 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
3375 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
3376 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
3377 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
3378 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
3379 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
3380 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
3381 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
3382 1030.06, 1037.25, 1044.45
3383 };
3384
3385 for (int ip = 0; ip < ctl->met_np; ip++)
3386 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3387
3388 } else if (7 == ctl->met_press_level_def) {
3389
3390 ctl->met_np = 59;
3391
3392 const double press[59] = {
3393 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
3394 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
3395 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
3396 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
3397 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
3398 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
3399 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
3400 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
3401 1028.53, 1046.13
3402 };
3403
3404 for (int ip = 0; ip < ctl->met_np; ip++)
3405 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3406
3407 } else {
3408 ERRMSG("Use values between 3 and 7.");
3409 }
3410
3411 if (ctl->met_np > EP)
3412 ERRMSG("Recompile with larger EP to use this pressure level definition!");
3413}
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2646
int met_np
Number of target pressure levels.
Definition: mptrac.h:2640
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2643

◆ 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 3417 of file mptrac.c.

3420 {
3421
3422 int ilo = 0;
3423 int ihi = n - 1;
3424 int i = (ihi + ilo) >> 1;
3425
3426 if (xx[i] < xx[i + 1])
3427 while (ihi > ilo + 1) {
3428 i = (ihi + ilo) >> 1;
3429 if (xx[i] > x)
3430 ihi = i;
3431 else
3432 ilo = i;
3433 } else
3434 while (ihi > ilo + 1) {
3435 i = (ihi + ilo) >> 1;
3436 if (xx[i] <= x)
3437 ihi = i;
3438 else
3439 ilo = i;
3440 }
3441
3442 return ilo;
3443}

◆ 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 3447 of file mptrac.c.

3451 {
3452
3453 int ilo = 0;
3454 int ihi = n - 1;
3455 int i = (ihi + ilo) >> 1;
3456
3457 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
3458 return ig;
3459
3460 if (xx[i] < xx[i + 1])
3461 while (ihi > ilo + 1) {
3462 i = (ihi + ilo) >> 1;
3463 if (xx[i] > x)
3464 ihi = i;
3465 else
3466 ilo = i;
3467 } else
3468 while (ihi > ilo + 1) {
3469 i = (ihi + ilo) >> 1;
3470 if (xx[i] <= x)
3471 ihi = i;
3472 else
3473 ilo = i;
3474 }
3475
3476 return ilo;
3477}

◆ 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 3481 of file mptrac.c.

3484 {
3485
3486 /* Calculate index... */
3487 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
3488
3489 /* Check range... */
3490 if (i < 0)
3491 return 0;
3492 else if (i > n - 2)
3493 return n - 2;
3494 else
3495 return i;
3496}

◆ 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 3500 of file mptrac.c.

3506 {
3507
3508 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
3509 np, height_ap, 0);
3510 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
3511 np, height_ap, ind[0]);
3512 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
3513 np, height_ap, ind[1]);
3514 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
3515 np, height_ap, ind[2]);
3516}
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:3447
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 3520 of file mptrac.c.

3525 {
3526
3527 /* Set timer... */
3528 SELECT_TIMER("MODULE_ADVECT", "PHYSICS");
3529
3530 /* Use omega vertical velocity... */
3531 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
3532
3533 /* Loop over particles... */
3534 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3535
3536 /* Init... */
3538 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
3539 x[3] = { 0, 0, 0 };
3540
3541 /* Loop over integration nodes... */
3542 for (int i = 0; i < ctl->advect; i++) {
3543
3544 /* Set position... */
3545 if (i == 0) {
3546 dts = 0.0;
3547 x[0] = atm->lon[ip];
3548 x[1] = atm->lat[ip];
3549 x[2] = atm->p[ip];
3550 } else {
3551 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3552 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
3553 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
3554 x[2] = atm->p[ip] + dts * w[i - 1];
3555 }
3556 const double tm = atm->time[ip] + dts;
3557
3558 /* Interpolate meteo data on pressure levels... */
3559 if (ctl->advect_vert_coord == 0) {
3560 intpol_met_time_3d(met0, met0->u, met1, met1->u,
3561 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3562 intpol_met_time_3d(met0, met0->v, met1, met1->v,
3563 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3564 intpol_met_time_3d(met0, met0->w, met1, met1->w,
3565 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3566 }
3567
3568 /* Interpolate meteo data on model levels... */
3569 else {
3570 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
3571 met1, met1->pl, met1->ul,
3572 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3573 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
3574 met1, met1->pl, met1->vl,
3575 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3576 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
3577 met1, met1->pl, met1->wl,
3578 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3579 }
3580
3581 /* Get mean wind... */
3582 double k = 1.0;
3583 if (ctl->advect == 2)
3584 k = (i == 0 ? 0.0 : 1.0);
3585 else if (ctl->advect == 4)
3586 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3587 um += k * u[i];
3588 vm += k * v[i];
3589 wm += k * w[i];
3590 }
3591
3592 /* Set new position... */
3593 atm->time[ip] += cache->dt[ip];
3594 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3595 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3596 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3597 atm->p[ip] += cache->dt[ip] * wm;
3598 }
3599 }
3600
3601 /* Use zeta or eta vertical velocity... */
3602 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
3603
3604 /* Select quantity index depending on coordinate... */
3605 const int qnt = (ctl->advect_vert_coord == 1
3606 ? ctl->qnt_zeta : ctl->qnt_eta);
3607
3608 /* Loop over particles... */
3609 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3610
3611 /* Convert pressure to vertical coordinate (zeta or eta)... */
3613 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
3614 met1, met1->pl, met1->zetal,
3615 atm->time[ip], atm->p[ip],
3616 atm->lon[ip], atm->lat[ip],
3617 &atm->q[qnt][ip], ci, cw, 1);
3618
3619 /* Init... */
3620 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
3621 wdotm = 0, x[3] = { 0, 0, 0 };
3622
3623 /* Loop over integration nodes (Runge–Kutta steps)... */
3624 for (int i = 0; i < ctl->advect; i++) {
3625
3626 /* Set position... */
3627 if (i == 0) {
3628 dts = 0.0;
3629 x[0] = atm->lon[ip];
3630 x[1] = atm->lat[ip];
3631 x[2] = atm->q[qnt][ip];
3632 } else {
3633 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3634 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
3635 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
3636 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
3637 }
3638
3639 const double tm = atm->time[ip] + dts;
3640
3641 /* Interpolate meteo data... */
3642 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
3643 met1, met1->zetal, met1->ul,
3644 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3645 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
3646 met1, met1->zetal, met1->vl,
3647 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3648 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
3649 met1, met1->zetal, met1->zeta_dotl,
3650 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
3651
3652 /* Compute Runge–Kutta weights... */
3653 double k = 1.0;
3654 if (ctl->advect == 2)
3655 k = (i == 0 ? 0.0 : 1.0);
3656 else if (ctl->advect == 4)
3657 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3658
3659 um += k * u[i];
3660 vm += k * v[i];
3661 wdotm += k * wdot[i];
3662 }
3663
3664 /* Update particle position... */
3665 atm->time[ip] += cache->dt[ip];
3666 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3667 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3668 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3669 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
3670
3671 /* Convert vertical coordinate (zeta or eta) back to pressure... */
3672 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
3673 met1, met1->zetal, met1->pl,
3674 atm->time[ip],
3675 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
3676 &atm->p[ip], ci, cw, 1);
3677 }
3678 }
3679}
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:3034
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:2746
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1458
#define SELECT_TIMER(id, group)
Select and start a timer with specific attributes.
Definition: mptrac.h:2184
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:655
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:673
double time[NP]
Time [s].
Definition: mptrac.h:3240
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3249
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3246
int np
Number of air parcels.
Definition: mptrac.h:3237
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3252
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3243
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3310
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2421
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2715
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2412
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:2719
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3653
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3611
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3647
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3644
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3605
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3641
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3608
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3638
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3650
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 3683 of file mptrac.c.

3688 {
3689
3690 /* Check parameters... */
3691 if (ctl->advect_vert_coord != 1)
3692 return;
3693
3694 /* Set timer... */
3695 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS");
3696
3697 /* Loop over particles... */
3698 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
3699
3700 /* Initialize pressure consistent with zeta... */
3702 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
3703 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
3704 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
3705 }
3706}
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 3710 of file mptrac.c.

3716 {
3717
3718 /* Set timer... */
3719 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS");
3720
3721 /* Check quantity flags... */
3722 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
3723 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
3724 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
3725 return;
3726
3727 /* Loop over particles... */
3728 PARTICLE_LOOP(0, atm->np, 1,
3729 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3730
3731 /* Check latitude and pressure range... */
3732 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
3733 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
3734 continue;
3735
3736 /* Check surface layer... */
3737 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
3738 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
3739
3740 /* Get surface pressure... */
3741 double ps;
3743 INTPOL_2D(ps, 1);
3744
3745 /* Check pressure... */
3746 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
3747 continue;
3748
3749 /* Check height... */
3750 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
3751 continue;
3752
3753 /* Check zeta range... */
3754 if (ctl->bound_zetas > 0) {
3755 double t;
3756 INTPOL_3D(t, 1);
3757 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
3758 continue;
3759 }
3760
3761 /* Check planetary boundary layer... */
3762 if (ctl->bound_pbl) {
3763 double pbl;
3764 INTPOL_2D(pbl, 0);
3765 if (atm->p[ip] < pbl)
3766 continue;
3767 }
3768 }
3769
3770 /* Set mass and volume mixing ratio... */
3771 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
3772 atm->q[ctl->qnt_m][ip] =
3773 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
3774 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
3775 atm->q[ctl->qnt_vmr][ip] =
3776 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
3777
3778 /* Set CFC-10 volume mixing ratio... */
3779 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
3780 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
3781
3782 /* Set CFC-11 volume mixing ratio... */
3783 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
3784 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
3785
3786 /* Set CFC-12 volume mixing ratio... */
3787 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
3788 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
3789
3790 /* Set N2O volume mixing ratio... */
3791 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
3792 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
3793
3794 /* Set SF6 volume mixing ratio... */
3795 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
3796 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
3797
3798 /* Set age of air... */
3799 if (ctl->qnt_aoa >= 0)
3800 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
3801 }
3802}
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:385
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:909
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1997
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:892
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3471
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3477
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3465
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3468
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3474
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2490
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2229
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2499
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2845
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2794
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2484
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2767
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2232
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2782
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2800
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2788
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2773
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2779
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2776
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2493
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2487
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2496
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2791
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2770
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2785
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2836
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2848
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2839
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2842
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2797
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 3806 of file mptrac.c.

3811 {
3812
3813 /* Check quantities... */
3814 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
3815 return;
3816 if (ctl->molmass <= 0)
3817 ERRMSG("Molar mass is not defined!");
3818
3819 /* Set timer... */
3820 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS");
3821
3822 /* Allocate... */
3823 const int ensemble_mode = (ctl->nens > 0);
3824 const int np = atm->np;
3825 const int nz = ctl->chemgrid_nz;
3826 const int nx = ctl->chemgrid_nx;
3827 const int ny = ctl->chemgrid_ny;
3828 const int ngrid = nx * ny * nz;
3829 const int nens = ensemble_mode ? ctl->nens : 1;
3830
3831 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
3832 double *restrict const press =
3833 (double *) malloc((size_t) nz * sizeof(double));
3834 double *restrict const mass =
3835 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
3836 double *restrict const area =
3837 (double *) malloc((size_t) ny * sizeof(double));
3838 double *restrict const lon =
3839 (double *) malloc((size_t) nx * sizeof(double));
3840 double *restrict const lat =
3841 (double *) malloc((size_t) ny * sizeof(double));
3842
3843 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3844 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3845 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3846
3847 /* Set grid box size... */
3848 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
3849 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
3850 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
3851
3852 /* Set vertical coordinates... */
3853#ifdef _OPENACC
3854#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])
3855#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
3856#pragma acc parallel loop independent gang vector
3857#else
3858#pragma omp parallel for default(shared)
3859#endif
3860 for (int iz = 0; iz < nz; iz++) {
3861 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
3862 press[iz] = P(z[iz]);
3863 }
3864
3865 /* Set time interval for output... */
3866 const double t0 = tt - 0.5 * ctl->dt_mod;
3867 const double t1 = tt + 0.5 * ctl->dt_mod;
3868
3869 /* Get indices... */
3870#ifdef _OPENACC
3871#pragma acc parallel loop independent gang vector
3872#else
3873#pragma omp parallel for default(shared)
3874#endif
3875 for (int ip = 0; ip < np; ip++) {
3876 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
3877 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
3878 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
3879 if (atm->time[ip] < t0 || atm->time[ip] > t1
3880 || ixs[ip] < 0 || ixs[ip] >= nx
3881 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
3882 izs[ip] = -1;
3883 }
3884
3885 /* Set horizontal coordinates... */
3886#ifdef _OPENACC
3887#pragma acc parallel loop independent gang vector
3888#else
3889#pragma omp parallel for default(shared)
3890#endif
3891 for (int ix = 0; ix < nx; ix++)
3892 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3893
3894#ifdef _OPENACC
3895#pragma acc parallel loop independent gang vector
3896#else
3897#pragma omp parallel for default(shared)
3898#endif
3899 for (int iy = 0; iy < ny; iy++) {
3900 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3901 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3902 }
3903
3904 /* Get mass per grid box... */
3905#ifdef _OPENACC
3906#pragma acc parallel loop independent gang vector
3907#endif
3908 for (int ip = 0; ip < np; ip++) {
3909 if (izs[ip] >= 0) {
3910 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3911 if (ensemble_mode) {
3912 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3913 mass_idx += ens * ngrid;
3914 }
3915#ifdef _OPENACC
3916#pragma acc atomic update
3917#endif
3918 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
3919 }
3920 }
3921
3922 /* Assign grid data to air parcels ... */
3923#ifdef _OPENACC
3924#pragma acc parallel loop independent gang vector
3925#else
3926#pragma omp parallel for default(shared)
3927#endif
3928 for (int ip = 0; ip < np; ip++)
3929 if (izs[ip] >= 0) {
3930
3931 /* Interpolate temperature... */
3932 double temp;
3934 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
3935 press[izs[ip]],
3936 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
3937
3938 /* Set mass... */
3939 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3940 if (ensemble_mode) {
3941 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3942 mass_idx += ens * ngrid;
3943 }
3944
3945 /* Calculate volume mixing ratio... */
3946 const double m = mass[mass_idx];
3947 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
3948 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
3949 }
3950
3951 /* Free... */
3952#ifdef _OPENACC
3953#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
3954#endif
3955 free(mass);
3956 free(lon);
3957 free(lat);
3958 free(area);
3959 free(z);
3960 free(press);
3961 free(ixs);
3962 free(iys);
3963 free(izs);
3964}
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:499
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:290
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1488
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1665
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2806
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2893
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2890
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2908
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2911
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2899
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2902
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2535
int nens
Number of ensembles.
Definition: mptrac.h:3062
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2887
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2896
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2905
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2223
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2454
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 3968 of file mptrac.c.

3974 {
3975
3976 /* Set timer... */
3977 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS");
3978
3979 /* Loop over particles... */
3980 PARTICLE_LOOP(0, atm->np, 0,
3981 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3982
3983 /* Set H2O and O3 using meteo data... */
3985 if (ctl->qnt_Ch2o >= 0) {
3986 double h2o;
3987 INTPOL_3D(h2o, 1);
3988 SET_ATM(qnt_Ch2o, h2o);
3989 }
3990 if (ctl->qnt_Co3 >= 0) {
3991 double o3;
3992 INTPOL_3D(o3, 1);
3993 SET_ATM(qnt_Co3, o3);
3994 }
3995
3996 /* Set radical species... */
3997 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
3998 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3999 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
4000 atm->lat[ip], atm->p[ip]));
4001 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
4002 atm->lat[ip], atm->p[ip]));
4003 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
4004 atm->lat[ip], atm->p[ip]));
4005 }
4006}
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:87
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1684
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3459
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3462
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3456
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2457
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2460
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 4010 of file mptrac.c.

4015 {
4016
4017 /* Set timer... */
4018 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS");
4019
4020 /* Create random numbers... */
4021 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
4022
4023 /* Loop over particles... */
4024 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4025
4026 /* Interpolate surface pressure... */
4027 double ps;
4029 INTPOL_2D(ps, 1);
4030
4031 /* Initialize pressure range for vertical mixing... */
4032 double pbot = ps, ptop = ps;
4033
4034 /* Mixing in the PBL... */
4035 if (ctl->conv_mix_pbl) {
4036
4037 /* Interpolate PBL... */
4038 double pbl;
4039 INTPOL_2D(pbl, 0);
4040
4041 /* Set pressure range... */
4042 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
4043 }
4044
4045 /* Convective mixing... */
4046 if (ctl->conv_cape >= 0) {
4047
4048 /* Interpolate CAPE, CIN, and equilibrium level... */
4049 double cape, cin, pel;
4050 INTPOL_2D(cape, 0);
4051 INTPOL_2D(cin, 0);
4052 INTPOL_2D(pel, 0);
4053
4054 /* Set pressure range... */
4055 if (isfinite(cape) && cape >= ctl->conv_cape
4056 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
4057 ptop = GSL_MIN(ptop, pel);
4058 }
4059
4060 /* Apply vertical mixing... */
4061 if (ptop != pbot && atm->p[ip] >= ptop) {
4062
4063 /* Get density range... */
4064 double tbot, ttop;
4065 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
4066 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
4067 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
4068 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
4069 const double rhobot = pbot / tbot;
4070 const double rhotop = ptop / ttop;
4071
4072 /* Get new density... */
4073 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
4074
4075 /* Get pressure... */
4076 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
4077 }
4078 }
4079}
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:5250
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3307
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2758
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2755
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2752
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2761
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 4131 of file mptrac.c.

4135 {
4136
4137 /* Set timer... */
4138 SELECT_TIMER("MODULE_DECAY", "PHYSICS");
4139
4140 /* Check quantity flags... */
4141 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4142 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4143
4144 /* Loop over particles... */
4145 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
4146
4147 /* Get weighting factor... */
4148 const double w = tropo_weight(clim, atm, ip);
4149
4150 /* Set lifetime... */
4151 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
4152
4153 /* Calculate exponential decay... */
4154 const double aux = exp(-cache->dt[ip] / tdec);
4155 if (ctl->qnt_m >= 0) {
4156 if (ctl->qnt_mloss_decay >= 0)
4157 atm->q[ctl->qnt_mloss_decay][ip]
4158 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4159 atm->q[ctl->qnt_m][ip] *= aux;
4160 if (ctl->qnt_loss_rate >= 0)
4161 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
4162 }
4163 if (ctl->qnt_vmr >= 0)
4164 atm->q[ctl->qnt_vmr][ip] *= aux;
4165 }
4166}
double tropo_weight(const clim_t *clim, const atm_t *atm, const int ip)
Computes a weighting factor based on tropopause pressure.
Definition: mptrac.c:11990
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2388
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2385
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2812
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2809
Here is the call graph for this function:

◆ module_diff_meso()

void module_diff_meso ( const ctl_t ctl,
cache_t cache,
met_t met0,
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 4170 of file mptrac.c.

4175 {
4176
4177 /* Set timer... */
4178 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS");
4179
4180 /* Create random numbers... */
4181 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4182
4183 /* Loop over particles... */
4184 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4185
4186 /* Get indices... */
4187 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
4188 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
4189 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
4190
4191 /* Get standard deviations of local wind data... */
4192 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
4193 for (int i = 0; i < 2; i++)
4194 for (int j = 0; j < 2; j++)
4195 for (int k = 0; k < 2; k++) {
4196 umean += met0->u[ix + i][iy + j][iz + k];
4197 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
4198 vmean += met0->v[ix + i][iy + j][iz + k];
4199 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
4200 wmean += met0->w[ix + i][iy + j][iz + k];
4201 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
4202
4203 umean += met1->u[ix + i][iy + j][iz + k];
4204 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
4205 vmean += met1->v[ix + i][iy + j][iz + k];
4206 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
4207 wmean += met1->w[ix + i][iy + j][iz + k];
4208 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
4209 }
4210 usig = usig / 16.f - SQR(umean / 16.f);
4211 usig = (usig > 0 ? sqrtf(usig) : 0);
4212 vsig = vsig / 16.f - SQR(vmean / 16.f);
4213 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
4214 wsig = wsig / 16.f - SQR(wmean / 16.f);
4215 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
4216
4217 /* Set temporal correlations for mesoscale fluctuations... */
4218 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
4219 const double r2 = sqrt(1 - r * r);
4220
4221 /* Calculate horizontal mesoscale wind fluctuations... */
4222 if (ctl->turb_mesox > 0) {
4223 cache->uvwp[ip][0] =
4224 (float) (r * cache->uvwp[ip][0] +
4225 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
4226 atm->lon[ip] +=
4227 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
4228
4229 cache->uvwp[ip][1] =
4230 (float) (r * cache->uvwp[ip][1] +
4231 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
4232 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
4233 }
4234
4235 /* Calculate vertical mesoscale wind fluctuations... */
4236 if (ctl->turb_mesoz > 0) {
4237 cache->uvwp[ip][2] =
4238 (float) (r * cache->uvwp[ip][2] +
4239 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
4240 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
4241 }
4242 }
4243}
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3304
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2749
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2545
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2746
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 4247 of file mptrac.c.

4252 {
4253
4254 /* Set timer... */
4255 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS");
4256
4257 /* Create random numbers... */
4258 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4259
4260 /* Loop over particles... */
4261 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4262
4263 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
4264 tau_u = 300., tau_w = 100.;
4265
4266 /* Get surface and PBL pressure... */
4267 double pbl, ps;
4269 INTPOL_2D(ps, 1);
4270 INTPOL_2D(pbl, 0);
4271
4272 /* Boundary layer... */
4273 if (atm->p[ip] >= pbl) {
4274
4275 /* Calculate heights... */
4276 const double p = MIN(atm->p[ip], ps);
4277 const double zs = Z(ps);
4278 const double z = 1e3 * (Z(p) - zs);
4279 const double zi = 1e3 * (Z(pbl) - zs);
4280 const double zratio = z / zi;
4281
4282 /* Calculate friction velocity... */
4283 double ess, nss, h2o, t;
4284 INTPOL_2D(ess, 0);
4285 INTPOL_2D(nss, 0);
4286 INTPOL_3D(t, 1);
4287 INTPOL_3D(h2o, 0);
4288 const double rho = RHO(p, TVIRT(t, h2o));
4289 const double tau = sqrt(SQR(ess) + SQR(nss));
4290 const double ustar = sqrt(tau / rho);
4291
4292 /* Get surface sensible heat flux... */
4293 double shf;
4294 INTPOL_2D(shf, 1);
4295
4296 /* Stable or neutral conditions... */
4297 if (shf <= 0) {
4298
4299 /* Calcalute turbulent velocity variances... */
4300 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
4301 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
4302
4303 /* Calculate derivative dsig_w/dz... */
4304 dsigw_dz = -1.3 * ustar / zi;
4305
4306 /* Calcalute Lagrangian timescales... */
4307 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
4308 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
4309 }
4310
4311 /* Unstable conditions... */
4312 else {
4313
4314 /* Convective velocity... */
4315 const double wstar =
4316 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
4317
4318 /* Calcalute turbulent velocity variances... */
4319 sig_u = 1e-2
4320 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
4321 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
4322 * pow(zratio, 2.0 / 3.0)
4323 + (1.8 - 1.4 * zratio) * SQR(ustar));
4324
4325 /* Calculate derivative dsig_w/dz... */
4326 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
4327 * (0.8 *
4328 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
4329 - 1.8 * pow(zratio, 2.0 / 3.0)));
4330
4331 /* Calculate Lagrangian timescales... */
4332 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
4333 const double eps =
4334 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
4335 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
4336 tau_u = 2 * SQR(sig_u) / (C0 * eps);
4337 tau_w = 2 * SQR(sig_w) / (C0 * eps);
4338 }
4339 }
4340
4341 /* Set minimum values... */
4342 sig_u = MAX(sig_u, 0.25);
4343 sig_w = MAX(sig_w, 0.1);
4344 tau_u = MAX(tau_u, 300.);
4345 tau_w = MAX(tau_w, 100.);
4346
4347 /* Update perturbations... */
4348 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
4349 const double ru2 = sqrt(1.0 - SQR(ru));
4350 cache->uvwp[ip][0]
4351 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
4352 cache->uvwp[ip][1]
4353 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
4354
4355 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
4356 const double rw2 = sqrt(1.0 - SQR(rw));
4357 cache->uvwp[ip][2]
4358 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
4359 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
4360
4361 /* Calculate new air parcel position... */
4362 atm->lon[ip] +=
4363 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
4364 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
4365 atm->p[ip] +=
4366 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
4367 }
4368}
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1903
#define KARMAN
Karman's constant.
Definition: mptrac.h:280
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1857
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:692
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_TROP and TURB_DZ_PBL, TURB_DZ_TROP, TURB_DZ_STRAT define horizontal and vertical diffusivities (in units of m**2 s**-1) in the PBL, troposphere, and stratosphere, respectively. The control parameter DIFF_MIX_PBL is used to switch vertical mixing in the PBL on or off.
  • Apply the following settings to reproduce Stohl et al. (2005): TURB_DX_PBL = 50 TURB_DX_TROP = 50 TURB_DX_STRAT = 0 TURB_DX_PBL = 0 TURB_DX_TROP = 0 TURB_DX_STRAT = 0.1 TURB_MESOX = 0.16 TURB_MESOZ = 0.16 DIFF_MIX_PBL = 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_DX_PBL = 0 TURB_DX_TROP = 1.5 TURB_DX_STRAT = 1.5 TURB_MESOX = 0 TURB_MESOZ = 0 DIFF_MIX_PBL = 1
Author
Lars Hoffmann

Definition at line 4372 of file mptrac.c.

4378 {
4379
4380 /* Set timer... */
4381 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS");
4382
4383 /* Create random numbers... */
4384 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4385
4386 /* Loop over particles... */
4387 PARTICLE_LOOP(0, atm->np, 1,
4388 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4389
4390 /* Get PBL and surface pressure... */
4391 double pbl, ps;
4393 INTPOL_2D(pbl, 1);
4394 INTPOL_2D(ps, 0);
4395
4396 /* Get weighting factors... */
4397 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
4398 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
4399 const double wstrat = 1.0 - wpbl - wtrop;
4400
4401 /* Set diffusivity... */
4402 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
4403 + wstrat * ctl->turb_dx_strat;
4404 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
4405 + wstrat * ctl->turb_dz_strat;
4406
4407 /* Horizontal turbulent diffusion... */
4408 if (dx > 0) {
4409 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
4410 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
4411 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
4412 }
4413
4414 /* Vertical turbulent diffusion... */
4415 if (dz > 0) {
4416 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
4417 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
4418 }
4419 }
4420}
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:7677
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2740
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2734
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2731
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2728
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2743
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2737
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 4424 of file mptrac.c.

4429 {
4430
4431 /* Set timer... */
4432 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS");
4433
4434 /* Check quantity flags... */
4435 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4436 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4437
4438 /* Loop over particles... */
4439 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4440
4441 /* Get surface pressure... */
4442 double ps;
4444 INTPOL_2D(ps, 1);
4445
4446 /* Check whether particle is above the surface layer... */
4447 if (atm->p[ip] < ps - ctl->dry_depo_dp)
4448 continue;
4449
4450 /* Set depth of surface layer... */
4451 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
4452
4453 /* Calculate sedimentation velocity for particles... */
4454 double v_dep;
4455 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
4456
4457 /* Get temperature... */
4458 double t;
4459 INTPOL_3D(t, 1);
4460
4461 /* Set deposition velocity... */
4462 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4463 atm->q[ctl->qnt_rhop][ip]);
4464 }
4465
4466 /* Use explicit sedimentation velocity for gases... */
4467 else
4468 v_dep = ctl->dry_depo_vdep;
4469
4470 /* Calculate loss of mass based on deposition velocity... */
4471 const double aux = exp(-cache->dt[ip] * v_dep / dz);
4472 if (ctl->qnt_m >= 0) {
4473 if (ctl->qnt_mloss_dry >= 0)
4474 atm->q[ctl->qnt_mloss_dry][ip]
4475 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4476 atm->q[ctl->qnt_m][ip] *= aux;
4477 if (ctl->qnt_loss_rate >= 0)
4478 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
4479 }
4480 if (ctl->qnt_vmr >= 0)
4481 atm->q[ctl->qnt_vmr][ip] *= aux;
4482 }
4483}
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:11755
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2238
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2235
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2968
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2382
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2971
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 4487 of file mptrac.c.

4493 {
4494
4495 /* Set timer... */
4496 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS");
4497
4498 /* Check quantity flags... */
4499 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4500 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4501
4502 /* Parameter of SO2 correction... */
4503 const double a = 3.12541941e-06;
4504 const double b = -5.72532259e-01;
4505 const double low = pow(1. / a, 1. / b);
4506
4507 /* Loop over particles... */
4508 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4509
4510 /* Check whether particle is inside cloud... */
4511 double lwc, rwc;
4513 INTPOL_3D(lwc, 1);
4514 INTPOL_3D(rwc, 0);
4515 if (!(lwc > 0 || rwc > 0))
4516 continue;
4517
4518 /* Get temperature... */
4519 double t;
4520 INTPOL_3D(t, 0);
4521
4522 /* Get molecular density... */
4523 const double M = MOLEC_DENS(atm->p[ip], t);
4524
4525 /* Reaction rate (Berglen et al., 2004)... */
4526 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
4527
4528 /* Henry constant of SO2... */
4529 const double H_SO2 =
4530 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
4531 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
4532
4533 /* Henry constant of H2O2... */
4534 const double H_h2o2 =
4535 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
4536
4537 /* Correction factor for high SO2 concentration
4538 (if qnt_Cx is defined, the correction is switched on)... */
4539 double cor = 1.0;
4540 if (ctl->qnt_Cx >= 0)
4541 cor = atm->q[ctl->qnt_Cx][ip] >
4542 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
4543
4544 const double h2o2 = H_h2o2
4545 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
4546 * M * cor * 1000. / AVO; /* unit: mol/L */
4547
4548 /* Volume water content in cloud [m^3 m^(-3)]... */
4549 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
4550 const double CWC = (lwc + rwc) * rho_air / 1e3;
4551
4552 /* Calculate exponential decay (Rolph et al., 1992)... */
4553 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
4554 const double aux = exp(-cache->dt[ip] * rate_coef);
4555 if (ctl->qnt_m >= 0) {
4556 if (ctl->qnt_mloss_h2o2 >= 0)
4557 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
4558 atm->q[ctl->qnt_m][ip] *= aux;
4559 if (ctl->qnt_loss_rate >= 0)
4560 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4561 }
4562 if (ctl->qnt_vmr >= 0)
4563 atm->q[ctl->qnt_vmr][ip] *= aux;
4564 }
4565}
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:250
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1198
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:320
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2373
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 4569 of file mptrac.c.

4574 {
4575
4576 double t;
4577
4578 /* Set timer... */
4579 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS");
4580
4581 /* Save pressure... */
4582 if (ctl->isosurf == 1) {
4583 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
4584 cache->iso_var[ip] = atm->p[ip];
4585 }
4586 }
4587
4588 /* Save density... */
4589 else if (ctl->isosurf == 2) {
4590 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4592 INTPOL_3D(t, 1);
4593 cache->iso_var[ip] = atm->p[ip] / t;
4594 }
4595 }
4596
4597 /* Save potential temperature... */
4598 else if (ctl->isosurf == 3) {
4599 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4601 INTPOL_3D(t, 1);
4602 cache->iso_var[ip] = THETA(atm->p[ip], t);
4603 }
4604 }
4605
4606 /* Read balloon pressure data... */
4607 else if (ctl->isosurf == 4) {
4608
4609 /* Write info... */
4610 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
4611
4612 /* Open file... */
4613 FILE *in;
4614 if (!(in = fopen(ctl->balloon, "r")))
4615 ERRMSG("Cannot open file!");
4616
4617 /* Read pressure time series... */
4618 char line[LEN];
4619 while (fgets(line, LEN, in))
4620 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
4621 &(cache->iso_ps[cache->iso_n])) == 2)
4622 if ((++cache->iso_n) > NP)
4623 ERRMSG("Too many data points!");
4624
4625 /* Check number of points... */
4626 if (cache->iso_n < 1)
4627 ERRMSG("Could not read any data!");
4628
4629 /* Close file... */
4630 fclose(in);
4631
4632 /* Update of cache data on device... */
4633 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4634 }
4635}
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:7341
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1828
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:359
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3298
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3301
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3295
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3292
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2712
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2709
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 4639 of file mptrac.c.

4644 {
4645
4646 /* Set timer... */
4647 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS");
4648
4649 /* Loop over particles... */
4650 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4651
4652 /* Init... */
4653 double t;
4655
4656 /* Restore pressure... */
4657 if (ctl->isosurf == 1)
4658 atm->p[ip] = cache->iso_var[ip];
4659
4660 /* Restore density... */
4661 else if (ctl->isosurf == 2) {
4662 INTPOL_3D(t, 1);
4663 atm->p[ip] = cache->iso_var[ip] * t;
4664 }
4665
4666 /* Restore potential temperature... */
4667 else if (ctl->isosurf == 3) {
4668 INTPOL_3D(t, 1);
4669 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
4670 }
4671
4672 /* Interpolate pressure... */
4673 else if (ctl->isosurf == 4) {
4674 if (atm->time[ip] <= cache->iso_ts[0])
4675 atm->p[ip] = cache->iso_ps[0];
4676 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
4677 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
4678 else {
4679 const int idx =
4680 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
4681 atm->p[ip] =
4682 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
4683 cache->iso_ps[idx + 1], atm->time[ip]);
4684 }
4685 }
4686 }
4687}
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 4745 of file mptrac.c.

4751 {
4752
4753 /* Set timer... */
4754 SELECT_TIMER("MODULE_METEO", "PHYSICS");
4755
4756 /* Check quantity flags... */
4757 if (ctl->qnt_tsts >= 0)
4758 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
4759 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
4760
4761 /* Loop over particles... */
4762 PARTICLE_LOOP(0, atm->np, 0,
4763 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4764
4765 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
4766 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
4767 o3, lwc, rwc, iwc, swc, cc, z, zt;
4768
4769 /* Interpolate meteo data... */
4771 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
4772
4773 /* Set quantities... */
4774 SET_ATM(qnt_ps, ps);
4775 SET_ATM(qnt_ts, ts);
4776 SET_ATM(qnt_zs, zs);
4777 SET_ATM(qnt_us, us);
4778 SET_ATM(qnt_vs, vs);
4779 SET_ATM(qnt_ess, ess);
4780 SET_ATM(qnt_nss, nss);
4781 SET_ATM(qnt_shf, shf);
4782 SET_ATM(qnt_lsm, lsm);
4783 SET_ATM(qnt_sst, sst);
4784 SET_ATM(qnt_pbl, pbl);
4785 SET_ATM(qnt_pt, pt);
4786 SET_ATM(qnt_tt, tt);
4787 SET_ATM(qnt_zt, zt);
4788 SET_ATM(qnt_h2ot, h2ot);
4789 SET_ATM(qnt_zg, z);
4790 SET_ATM(qnt_p, atm->p[ip]);
4791 SET_ATM(qnt_t, t);
4792 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
4793 SET_ATM(qnt_u, u);
4794 SET_ATM(qnt_v, v);
4795 SET_ATM(qnt_w, w);
4796 SET_ATM(qnt_h2o, h2o);
4797 SET_ATM(qnt_o3, o3);
4798 SET_ATM(qnt_lwc, lwc);
4799 SET_ATM(qnt_rwc, rwc);
4800 SET_ATM(qnt_iwc, iwc);
4801 SET_ATM(qnt_swc, swc);
4802 SET_ATM(qnt_cc, cc);
4803 SET_ATM(qnt_pct, pct);
4804 SET_ATM(qnt_pcb, pcb);
4805 SET_ATM(qnt_cl, cl);
4806 SET_ATM(qnt_plcl, plcl);
4807 SET_ATM(qnt_plfc, plfc);
4808 SET_ATM(qnt_pel, pel);
4809 SET_ATM(qnt_cape, cape);
4810 SET_ATM(qnt_cin, cin);
4811 SET_ATM(qnt_o3c, o3c);
4812 SET_ATM(qnt_hno3,
4813 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
4814 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
4815 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4816 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
4817 atm->lat[ip], atm->p[ip]));
4818 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
4819 atm->lat[ip], atm->p[ip]));
4820 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
4821 atm->lat[ip], atm->p[ip]));
4822 SET_ATM(qnt_vh, sqrt(u * u + v * v));
4823 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
4824 SET_ATM(qnt_psat, PSAT(t));
4825 SET_ATM(qnt_psice, PSICE(t));
4826 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
4827 SET_ATM(qnt_sh, SH(h2o));
4828 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
4829 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
4830 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
4831 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
4832 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
4833 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
4834 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
4835 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
4836 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
4837 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
4838 SET_ATM(qnt_pv, pv);
4839 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
4840 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
4841 SET_ATM(qnt_tnat,
4842 nat_temperature(atm->p[ip], h2o,
4843 clim_zm(&clim->hno3, atm->time[ip],
4844 atm->lat[ip], atm->p[ip])));
4845 SET_ATM(qnt_tsts,
4846 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
4847 }
4848}
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:7653
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:3246
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1563
#define H0
Scale height [km].
Definition: mptrac.h:270
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1536
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1804
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1640
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:982
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1610
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1779
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1512
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3450
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2451
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2424
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2445
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2418
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2448
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 4852 of file mptrac.c.

4856 {
4857
4858 /* Set timer... */
4859 SELECT_TIMER("MODULE_MIXING", "PHYSICS");
4860
4861 /* Allocate... */
4862 const int np = atm->np;
4863 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
4864 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
4865 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
4866
4867 /* Set grid box size... */
4868 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
4869 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
4870 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
4871
4872 /* Set time interval... */
4873 const double t0 = t - 0.5 * ctl->dt_mod;
4874 const double t1 = t + 0.5 * ctl->dt_mod;
4875
4876 /* Get indices... */
4877#ifdef _OPENACC
4878#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
4879#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
4880#pragma acc parallel loop independent gang vector
4881#else
4882#pragma omp parallel for default(shared)
4883#endif
4884 for (int ip = 0; ip < np; ip++) {
4885 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
4886 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
4887 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
4888 if (atm->time[ip] < t0 || atm->time[ip] > t1
4889 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
4890 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
4891 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
4892 izs[ip] = -1;
4893 }
4894
4895 /* Calculate interparcel mixing... */
4896 const int use_ensemble = (ctl->nens > 0);
4897
4898 const int quantities[] = {
4899 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
4900 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
4901 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
4902 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
4903 ctl->qnt_Csf6, ctl->qnt_aoa, ctl->qnt_Arn222, ctl->qnt_Apb210,
4904 ctl->qnt_Abe7, ctl->qnt_Acs137, ctl->qnt_Ai131, ctl->qnt_Axe133
4905 };
4906 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
4907
4908 for (int i = 0; i < n_qnt; i++)
4909 if (quantities[i] >= 0)
4910 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
4911 use_ensemble);
4912
4913 /* Free... */
4914#ifdef _OPENACC
4915#pragma acc exit data delete(ixs,iys,izs)
4916#endif
4917 free(ixs);
4918 free(iys);
4919 free(izs);
4920}
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:4924
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2466
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2869
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2866
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2478
int qnt_Acs137
Quantity array index for radioactive activity of Cs-137.
Definition: mptrac.h:2511
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2863
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2463
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2878
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2469
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2881
int qnt_Ai131
Quantity array index for radioactive activity of I-131.
Definition: mptrac.h:2514
int qnt_Apb210
Quantity array index for radioactive activity of Pb-210.
Definition: mptrac.h:2505
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2472
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2860
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2872
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2884
int qnt_Axe133
Quantity array index for radioactive activity of Xe-133.
Definition: mptrac.h:2517
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2481
int qnt_Abe7
Quantity array index for radioactive activity of Be-7.
Definition: mptrac.h:2508
int qnt_Arn222
Quantity array index for radioactive activity of Rn-222.
Definition: mptrac.h:2502
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2475
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2875
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 4924 of file mptrac.c.

4932 {
4933
4934 const int np = atm->np;
4935 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
4936 const int nens = use_ensemble ? ctl->nens : 1;
4937 const int total_grid = ngrid * nens;
4938
4939 double *restrict const cmean =
4940 (double *) malloc((size_t) total_grid * sizeof(double));
4941 int *restrict const count =
4942 (int *) malloc((size_t) total_grid * sizeof(int));
4943
4944 /* Init... */
4945#ifdef _OPENACC
4946#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
4947#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
4948#pragma acc parallel loop independent gang vector
4949#else
4950#ifdef __NVCOMPILER
4951#pragma novector
4952#endif
4953#pragma omp parallel for
4954#endif
4955 for (int i = 0; i < total_grid; i++) {
4956 count[i] = 0;
4957 cmean[i] = 0.0;
4958 }
4959
4960 /* Loop over particles... */
4961#ifdef _OPENACC
4962#pragma acc parallel loop independent gang vector
4963#endif
4964 for (int ip = 0; ip < np; ip++)
4965 if (izs[ip] >= 0) {
4966 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4967 const int idx =
4968 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4969 ctl->mixing_nz);
4970#ifdef _OPENACC
4971#pragma acc atomic update
4972#endif
4973 cmean[idx] += atm->q[qnt_idx][ip];
4974#ifdef _OPENACC
4975#pragma acc atomic update
4976#endif
4977 count[idx]++;
4978 }
4979
4980 /* Compute means... */
4981#ifdef _OPENACC
4982#pragma acc parallel loop independent gang vector
4983#else
4984#ifdef __NVCOMPILER
4985#pragma novector
4986#endif
4987#pragma omp parallel for
4988#endif
4989 for (int i = 0; i < total_grid; i++)
4990 if (count[i] > 0)
4991 cmean[i] /= count[i];
4992
4993 /* Interparcel mixing... */
4994#ifdef _OPENACC
4995#pragma acc parallel loop independent gang vector
4996#else
4997#pragma omp parallel for
4998#endif
4999 for (int ip = 0; ip < np; ip++) {
5000 if (izs[ip] >= 0) {
5001 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5002
5003 double mixparam = 1.0;
5004 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
5005 const double w = tropo_weight(clim, atm, ip);
5006 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
5007 }
5008
5009 const int idx =
5010 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5011 ctl->mixing_nz);
5012 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
5013 }
5014 }
5015
5016 /* Free... */
5017#ifdef _OPENACC
5018#pragma acc exit data delete(cmean,count)
5019#endif
5020 free(cmean);
5021 free(count);
5022}
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2854
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2857
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 5026 of file mptrac.c.

5032 {
5033
5034 /* Set timer... */
5035 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS");
5036
5037 /* Check quantity flags... */
5038 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5039 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5040
5041 /* Parameter of SO2 correction... */
5042 const double a = 4.71572206e-08;
5043 const double b = -8.28782867e-01;
5044 const double low = pow(1. / a, 1. / b);
5045
5046 /* Loop over particles... */
5047 PARTICLE_LOOP(0, atm->np, 1,
5048 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5049
5050 /* Get temperature... */
5051 double t;
5053 INTPOL_3D(t, 1);
5054
5055 /* Calculate molecular density... */
5056 const double M = MOLEC_DENS(atm->p[ip], t);
5057
5058 /* Use constant reaction rate... */
5059 double k = NAN;
5060 if (ctl->oh_chem_reaction == 1)
5061 k = ctl->oh_chem[0];
5062
5063 /* Calculate bimolecular reaction rate... */
5064 else if (ctl->oh_chem_reaction == 2)
5065 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
5066
5067 /* Calculate termolecular reaction rate... */
5068 if (ctl->oh_chem_reaction == 3) {
5069
5070 /* Calculate rate coefficient for X + OH + M -> XOH + M
5071 (JPL Publication 19-05) ... */
5072 const double k0 =
5073 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
5074 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
5075 const double ki =
5076 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
5077 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
5078 const double c = log10(k0 * M / ki);
5079 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
5080 }
5081
5082 /* Correction factor for high SO2 concentration
5083 (if qnt_Cx is defined, the correction is switched on)... */
5084 double cor = 1;
5085 if (ctl->qnt_Cx >= 0)
5086 cor =
5087 atm->q[ctl->qnt_Cx][ip] >
5088 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
5089
5090 /* Calculate exponential decay... */
5091 const double rate_coef =
5092 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
5093 atm->lat[ip], atm->p[ip]) * M * cor;
5094 const double aux = exp(-cache->dt[ip] * rate_coef);
5095 if (ctl->qnt_m >= 0) {
5096 if (ctl->qnt_mloss_oh >= 0)
5097 atm->q[ctl->qnt_mloss_oh][ip]
5098 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5099 atm->q[ctl->qnt_m][ip] *= aux;
5100 if (ctl->qnt_loss_rate >= 0)
5101 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
5102 }
5103 if (ctl->qnt_vmr >= 0)
5104 atm->q[ctl->qnt_vmr][ip] *= aux;
5105 }
5106}
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2917
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2914
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2370
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 
)

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.
  • Checks and adjusts pressure levels:
    • Reflects pressure levels if they are below the minimum pressure in meteorological data.
    • Clamps pressure levels to the maximum pressure in meteorological data if they exceed a predefined threshold (300 hPa).
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.
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.
Pressure levels are adjusted based on meteorological data and a predefined threshold.
Author
Lars Hoffmann

Definition at line 5110 of file mptrac.c.

5114 {
5115
5116 /* Set timer... */
5117 SELECT_TIMER("MODULE_POSITION", "PHYSICS");
5118
5119 /* Loop over particles... */
5120 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
5121
5122 /* Init... */
5123 double ps;
5125
5126 /* Calculate modulo... */
5127 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
5128 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
5129
5130 /* Check latitude... */
5131 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
5132 if (atm->lat[ip] > 90) {
5133 atm->lat[ip] = 180 - atm->lat[ip];
5134 atm->lon[ip] += 180;
5135 }
5136 if (atm->lat[ip] < -90) {
5137 atm->lat[ip] = -180 - atm->lat[ip];
5138 atm->lon[ip] += 180;
5139 }
5140 }
5141
5142 /* Check longitude... */
5143 while (atm->lon[ip] < -180)
5144 atm->lon[ip] += 360;
5145 while (atm->lon[ip] >= 180)
5146 atm->lon[ip] -= 360;
5147
5148 /* Check pressure... */
5149 if (atm->p[ip] < met0->p[met0->np - 1]) {
5150 atm->p[ip] = met0->p[met0->np - 1];
5151 } else if (atm->p[ip] > 300.) {
5152 INTPOL_2D(ps, 1);
5153 if (atm->p[ip] > ps)
5154 atm->p[ip] = ps;
5155 }
5156 }
5157}

◆ 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 5161 of file mptrac.c.

5164 {
5165
5166 /* Set timer... */
5167 SELECT_TIMER("MODULE_RADIO_DECAY", "PHYSICS");
5168
5169 /* Set decay constants of radioactive species [s^-1]... */
5170 const double lambda_rn222 = log(2.0) / (3.8235 * 86400.0);
5171 const double lambda_pb210 = log(2.0) / (22.3 * 365.25 * 86400.0);
5172 const double lambda_be7 = log(2.0) / (53.22 * 86400.0);
5173 const double lambda_cs137 = log(2.0) / (30.05 * 365.25 * 86400.0);
5174 const double lambda_i131 = log(2.0) / (8.02 * 86400.0);
5175 const double lambda_xe133 = log(2.0) / (5.2474 * 86400.0);
5176
5177 /* Loop over particles... */
5178 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,atm)") {
5179
5180 /* Set timestep... */
5181 const double dt = cache->dt[ip];
5182
5183 /* Loss for Pb-210... */
5184 if (ctl->qnt_Apb210 >= 0)
5185 atm->q[ctl->qnt_Apb210][ip] *= exp(-dt * lambda_pb210);
5186
5187 /* Loss for Rn-222... */
5188 if (ctl->qnt_Arn222 >= 0) {
5189 const double old = atm->q[ctl->qnt_Arn222][ip];
5190 const double aux = exp(-dt * lambda_rn222);
5191 const double lost = old * (1.0 - aux);
5192 atm->q[ctl->qnt_Arn222][ip] = old * aux;
5193
5194 /* Parent-daughter process for Pb-210... */
5195 if (ctl->qnt_Apb210 >= 0)
5196 atm->q[ctl->qnt_Apb210][ip] += lost * lambda_pb210 / lambda_rn222;
5197 }
5198
5199 /* Loss for Be-7... */
5200 if (ctl->qnt_Abe7 >= 0)
5201 atm->q[ctl->qnt_Abe7][ip] *= exp(-dt * lambda_be7);
5202
5203 /* Loss for Cs-137... */
5204 if (ctl->qnt_Acs137 >= 0)
5205 atm->q[ctl->qnt_Acs137][ip] *= exp(-dt * lambda_cs137);
5206
5207 /* Loss for I-131... */
5208 if (ctl->qnt_Ai131 >= 0)
5209 atm->q[ctl->qnt_Ai131][ip] *= exp(-dt * lambda_i131);
5210
5211 /* Loss for Xe-133... */
5212 if (ctl->qnt_Axe133 >= 0)
5213 atm->q[ctl->qnt_Axe133][ip] *= exp(-dt * lambda_xe133);
5214 }
5215}

◆ 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 5219 of file mptrac.c.

5220 {
5221
5222 /* Initialize GSL random number generators... */
5223 gsl_rng_env_setup();
5224 if (omp_get_max_threads() > NTHREADS)
5225 ERRMSG("Too many threads!");
5226 for (int i = 0; i < NTHREADS; i++) {
5227 rng[i] = gsl_rng_alloc(gsl_rng_default);
5228 gsl_rng_set(rng[i], gsl_rng_default_seed
5229 + (long unsigned) (ntask * NTHREADS + i));
5230 }
5231
5232 /* Initialize cuRAND random number generators... */
5233#ifdef CURAND
5234 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
5235 CURAND_STATUS_SUCCESS)
5236 ERRMSG("Cannot create random number generator!");
5237 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
5238 CURAND_STATUS_SUCCESS)
5239 ERRMSG("Cannot set seed for random number generator!");
5240 if (curandSetStream
5241 (rng_curand,
5242 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
5243 CURAND_STATUS_SUCCESS)
5244 ERRMSG("Cannot set stream for random number generator!");
5245#endif
5246}
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:384

◆ 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 5250 of file mptrac.c.

5254 {
5255
5256 /* Use GSL random number generators... */
5257 if (ctl->rng_type == 0) {
5258
5259 /* Uniform distribution... */
5260 if (method == 0) {
5261#pragma omp parallel for default(shared)
5262 for (size_t i = 0; i < n; ++i)
5263 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
5264 }
5265
5266 /* Normal distribution... */
5267 else if (method == 1) {
5268#pragma omp parallel for default(shared)
5269 for (size_t i = 0; i < n; ++i)
5270 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
5271 }
5272
5273 /* Update of random numbers on device... */
5274#ifdef _OPENACC
5275 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
5276#pragma acc update device(rs[:n])
5277#endif
5278 }
5279
5280 /* Use Squares random number generator (Widynski, 2022)... */
5281 else if (ctl->rng_type == 1) {
5282
5283 /* Set key (don't change this!)... */
5284 const uint64_t key = 0xc8e4fd154ce32f6d;
5285
5286 /* Uniform distribution... */
5287#ifdef _OPENACC
5288#pragma acc data present(rs)
5289#pragma acc parallel loop independent gang vector
5290#else
5291#pragma omp parallel for default(shared)
5292#endif
5293 for (size_t i = 0; i < n + 1; ++i) {
5294 uint64_t r, t, x, y, z;
5295 y = x = (rng_ctr + i) * key;
5296 z = y + key;
5297 x = x * x + y;
5298 x = (x >> 32) | (x << 32);
5299 x = x * x + z;
5300 x = (x >> 32) | (x << 32);
5301 x = x * x + y;
5302 x = (x >> 32) | (x << 32);
5303 t = x = x * x + z;
5304 x = (x >> 32) | (x << 32);
5305 r = t ^ ((x * x + y) >> 32);
5306 rs[i] = (double) r / (double) UINT64_MAX;
5307 }
5308 rng_ctr += n + 1;
5309
5310 /* Normal distribution... */
5311 if (method == 1) {
5312#ifdef _OPENACC
5313#pragma acc parallel loop independent gang vector
5314#else
5315#pragma omp parallel for default(shared)
5316#endif
5317 for (size_t i = 0; i < n; i += 2) {
5318 const double r = sqrt(-2.0 * log(rs[i]));
5319 const double phi = 2.0 * M_PI * rs[i + 1];
5320 rs[i] = r * cosf((float) phi);
5321 rs[i + 1] = r * sinf((float) phi);
5322 }
5323 }
5324 }
5325
5326 /* Use cuRAND random number generators... */
5327 else if (ctl->rng_type == 2) {
5328#ifdef CURAND
5329#pragma acc host_data use_device(rs)
5330 {
5331
5332 /* Uniform distribution... */
5333 if (method == 0) {
5334 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
5335 CURAND_STATUS_SUCCESS)
5336 ERRMSG("Cannot create random numbers!");
5337 }
5338
5339 /* Normal distribution... */
5340 else if (method == 1) {
5341 if (curandGenerateNormalDouble
5342 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
5343 1.0) != CURAND_STATUS_SUCCESS)
5344 ERRMSG("Cannot create random numbers!");
5345 }
5346 }
5347#else
5348 ERRMSG("MPTRAC was compiled without cuRAND!");
5349#endif
5350 }
5351}
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2722

◆ 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 5355 of file mptrac.c.

5360 {
5361
5362 /* Set timer... */
5363 SELECT_TIMER("MODULE_SEDI", "PHYSICS");
5364
5365 /* Loop over particles... */
5366 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5367
5368 /* Get temperature... */
5369 double t;
5371 INTPOL_3D(t, 1);
5372
5373 /* Sedimentation velocity... */
5374 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
5375 atm->q[ctl->qnt_rhop][ip]);
5376
5377 /* Calculate pressure change... */
5378 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
5379 }
5380}
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 5384 of file mptrac.c.

5387 {
5388
5389 /* Set timer... */
5390 SELECT_TIMER("MODULE_SORT", "PHYSICS");
5391
5392 /* Allocate... */
5393 const int np = atm->np;
5394 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
5395 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
5396 if (a == NULL || p == NULL)
5397 ERRMSG("Out of memory!");
5398
5399#ifdef _OPENACC
5400#pragma acc enter data create(a[0:np],p[0:np])
5401#pragma acc data present(ctl,met0,atm,a,p)
5402#endif
5403
5404 /* Get box index... */
5405#ifdef _OPENACC
5406#pragma acc parallel loop independent gang vector
5407#else
5408#pragma omp parallel for default(shared)
5409#endif
5410 for (int ip = 0; ip < np; ip++) {
5411 a[ip] =
5412 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
5413 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
5414 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
5415 p[ip] = ip;
5416 }
5417
5418 /* Sorting... */
5419#ifdef THRUST
5420#ifdef _OPENACC
5421#pragma acc host_data use_device(a,p)
5422#endif
5423 thrustSortWrapper(a, np, p);
5424#else
5425 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
5426 if (perm_sz == NULL)
5427 ERRMSG("Out of memory!");
5428#ifdef _OPENACC
5429#pragma acc update self(a[0:np])
5430#endif
5431 gsl_sort_index(perm_sz, a, 1, (size_t) np);
5432 for (int ip = 0; ip < np; ++ip)
5433 p[ip] = (int) perm_sz[ip];
5434 free(perm_sz);
5435#ifdef _OPENACC
5436#pragma acc update device(p[0:np])
5437#endif
5438#endif
5439
5440 /* Sort data... */
5441 module_sort_help(atm->time, p, np);
5442 module_sort_help(atm->p, p, np);
5443 module_sort_help(atm->lon, p, np);
5444 module_sort_help(atm->lat, p, np);
5445 for (int iq = 0; iq < ctl->nq; iq++)
5446 module_sort_help(atm->q[iq], p, np);
5447
5448 /* Free... */
5449#ifdef _OPENACC
5450#pragma acc exit data delete(a,p)
5451#endif
5452 free(a);
5453 free(p);
5454}
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:5458
int nq
Number of quantities.
Definition: mptrac.h:2205
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 5458 of file mptrac.c.

5461 {
5462
5463 /* Allocate... */
5464 double *restrict const help =
5465 (double *) malloc((size_t) np * sizeof(double));
5466 if (help == NULL)
5467 ERRMSG("Out of memory!");
5468
5469 /* Reordering of array... */
5470#ifdef _OPENACC
5471#pragma acc enter data create(help[0:np])
5472#pragma acc data present(a,p,help)
5473#pragma acc parallel loop independent gang vector
5474#else
5475#pragma omp parallel for default(shared)
5476#endif
5477 for (int ip = 0; ip < np; ip++)
5478 help[ip] = a[p[ip]];
5479#ifdef _OPENACC
5480#pragma acc parallel loop independent gang vector
5481#else
5482#pragma omp parallel for default(shared)
5483#endif
5484 for (int ip = 0; ip < np; ip++)
5485 a[ip] = help[ip];
5486
5487 /* Free... */
5488#ifdef _OPENACC
5489#pragma acc exit data delete(help)
5490#endif
5491 free(help);
5492}

◆ module_timesteps()

void module_timesteps ( const ctl_t ctl,
cache_t cache,
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 5496 of file mptrac.c.

5501 {
5502
5503 /* Set timer... */
5504 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS");
5505
5506 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
5507 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
5508
5509 const int local =
5510 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
5511
5512 /* Loop over particles... */
5513 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
5514
5515 /* Set time step for each air parcel... */
5516 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
5517 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
5518 && ctl->direction * (atm->time[ip] - t) < 0))
5519 cache->dt[ip] = t - atm->time[ip];
5520 else
5521 cache->dt[ip] = 0.0;
5522
5523 /* Check horizontal boundaries of local meteo data... */
5524#ifndef DD
5525 int dd = 1;
5526#else
5527 int dd = 0;
5528#endif
5529 if (dd) {
5530 if (local && (atm->lon[ip] <= met0->lon[0]
5531 || atm->lon[ip] >= met0->lon[met0->nx - 1]
5532 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
5533 cache->dt[ip] = 0.0;
5534 } else {
5535 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
5536 cache->dt[ip] = 0;
5537 }
5538 }
5539}
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2526
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2532
int qnt_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2520
double t_start
Start time of simulation [s].
Definition: mptrac.h:2529

◆ 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 5543 of file mptrac.c.

5545 {
5546
5547 /* Set timer... */
5548 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS");
5549
5550 /* Set start time... */
5551 if (ctl->direction == 1) {
5552 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
5553 if (ctl->t_stop > 1e99)
5554 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
5555 } else {
5556 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
5557 if (ctl->t_stop > 1e99)
5558 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
5559 }
5560
5561 /* Check time interval... */
5562 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
5563 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
5564
5565 /* Round start time... */
5566 if (ctl->direction == 1)
5567 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
5568 else
5569 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
5570}

◆ 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 5574 of file mptrac.c.

5580 {
5581
5582 /* Set timer... */
5583 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS");
5584
5585 /* Loop over particles... */
5586 PARTICLE_LOOP(0, atm->np, 1,
5587 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5588
5589 /* Get temperature... */
5590 double t;
5592 INTPOL_3D(t, 1);
5593
5594 /* Get molecular density... */
5595 const double M = MOLEC_DENS(atm->p[ip], t);
5596
5597 /* Get total column ozone... */
5598 double o3c;
5599 INTPOL_2D(o3c, 1);
5600
5601 /* Get solar zenith angle... */
5602 const double sza =
5603 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
5604
5605 /* Get O(1D) volume mixing ratio... */
5606 const double o1d =
5607 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
5608
5609 /* Reactions for CFC-10... */
5610 if (ctl->qnt_Cccl4 >= 0) {
5611 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
5612 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
5613 atm->p[ip], sza, o3c);
5614 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5615 }
5616
5617 /* Reactions for CFC-11... */
5618 if (ctl->qnt_Cccl3f >= 0) {
5619 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
5620 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
5621 atm->p[ip], sza, o3c);
5622 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5623 }
5624
5625 /* Reactions for CFC-12... */
5626 if (ctl->qnt_Cccl2f2 >= 0) {
5627 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
5628 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
5629 atm->p[ip], sza, o3c);
5630 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5631 }
5632
5633 /* Reactions for N2O... */
5634 if (ctl->qnt_Cn2o >= 0) {
5635 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
5636 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
5637 atm->p[ip], sza, o3c);
5638 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5639 }
5640 }
5641}
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:145
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:524
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3351
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3348
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3342
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3345
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3447
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 5645 of file mptrac.c.

5650 {
5651
5652 /* Set timer... */
5653 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS");
5654
5655 /* Check quantity flags... */
5656 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5657 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5658
5659 /* Loop over particles... */
5660 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5661
5662 /* Check whether particle is below cloud top... */
5663 double pct;
5665 INTPOL_2D(pct, 1);
5666 if (!isfinite(pct) || atm->p[ip] <= pct)
5667 continue;
5668
5669 /* Get cloud bottom pressure... */
5670 double pcb;
5671 INTPOL_2D(pcb, 0);
5672
5673 /* Estimate precipitation rate (Pisso et al., 2019)... */
5674 double cl;
5675 INTPOL_2D(cl, 0);
5676 const double Is =
5677 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
5678 if (Is < 0.01)
5679 continue;
5680
5681 /* Check whether particle is inside or below cloud... */
5682 double lwc, rwc, iwc, swc;
5683 INTPOL_3D(lwc, 1);
5684 INTPOL_3D(rwc, 0);
5685 INTPOL_3D(iwc, 0);
5686 INTPOL_3D(swc, 0);
5687 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
5688
5689 /* Get temperature... */
5690 double t;
5691 INTPOL_3D(t, 0);
5692
5693 /* Calculate in-cloud scavenging coefficient... */
5694 double lambda = 0;
5695 if (inside) {
5696
5697 /* Calculate retention factor... */
5698 double eta;
5699 if (t > 273.15)
5700 eta = 1;
5701 else if (t <= 238.15)
5702 eta = ctl->wet_depo_ic_ret_ratio;
5703 else
5704 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
5705
5706 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5707 if (ctl->wet_depo_ic_a > 0)
5708 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
5709
5710 /* Use Henry's law for gases... */
5711 else if (ctl->wet_depo_ic_h[0] > 0) {
5712
5713 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5714 double h = ctl->wet_depo_ic_h[0]
5715 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
5716
5717 /* Use effective Henry's constant for SO2
5718 (Berglen, 2004; Simpson, 2012)... */
5719 if (ctl->wet_depo_so2_ph > 0) {
5720 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
5721 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
5722 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
5723 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
5724 }
5725
5726 /* Estimate depth of cloud layer... */
5727 const double dz = 1e3 * (Z(pct) - Z(pcb));
5728
5729 /* Calculate scavenging coefficient... */
5730 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5731 }
5732 }
5733
5734 /* Calculate below-cloud scavenging coefficient... */
5735 else {
5736
5737 /* Calculate retention factor... */
5738 double eta;
5739 if (t > 270)
5740 eta = 1;
5741 else
5742 eta = ctl->wet_depo_bc_ret_ratio;
5743
5744 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5745 if (ctl->wet_depo_bc_a > 0)
5746 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
5747
5748 /* Use Henry's law for gases... */
5749 else if (ctl->wet_depo_bc_h[0] > 0) {
5750
5751 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5752 const double h = ctl->wet_depo_bc_h[0]
5753 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
5754
5755 /* Estimate depth of cloud layer... */
5756 const double dz = 1e3 * (Z(pct) - Z(pcb));
5757
5758 /* Calculate scavenging coefficient... */
5759 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5760 }
5761 }
5762
5763 /* Calculate exponential decay of mass... */
5764 const double aux = exp(-cache->dt[ip] * lambda);
5765 if (ctl->qnt_m >= 0) {
5766 if (ctl->qnt_mloss_wet >= 0)
5767 atm->q[ctl->qnt_mloss_wet][ip]
5768 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5769 atm->q[ctl->qnt_m][ip] *= aux;
5770 if (ctl->qnt_loss_rate >= 0)
5771 atm->q[ctl->qnt_loss_rate][ip] += lambda;
5772 }
5773 if (ctl->qnt_vmr >= 0)
5774 atm->q[ctl->qnt_vmr][ip] *= aux;
5775 }
5776}
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2947
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2941
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2379
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2959
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2938
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2956
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2965
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2953
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2962
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2950
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2944

◆ mptrac_alloc()

void mptrac_alloc ( ctl_t **  ctl,
cache_t **  cache,
clim_t **  clim,
met_t **  met0,
met_t **  met1,
atm_t **  atm,
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.

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]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 5780 of file mptrac.c.

5787 {
5788
5789 /* Initialize GPU... */
5790#ifdef _OPENACC
5791 SELECT_TIMER("ACC_INIT", "INIT");
5792 int rank = 0;
5793#ifdef MPI
5794 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5795#endif
5796 if (acc_get_num_devices(acc_device_nvidia) <= 0)
5797 ERRMSG("Not running on a GPU device!");
5798 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
5799 acc_device_nvidia);
5800 acc_device_t device_type = acc_get_device_type();
5801 acc_init(device_type);
5802#endif
5803
5804 /* Allocate... */
5805 SELECT_TIMER("ALLOC", "MEMORY");
5806 ALLOC(*ctl, ctl_t, 1);
5807 ALLOC(*cache, cache_t, 1);
5808 ALLOC(*clim, clim_t, 1);
5809 ALLOC(*met0, met_t, 1);
5810 ALLOC(*met1, met_t, 1);
5811 ALLOC(*atm, atm_t, 1);
5812 ALLOC(*dd, dd_t, 1);
5813
5814 /* Create data region on GPU... */
5815#ifdef _OPENACC
5816 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY");
5817 ctl_t *ctlup = *ctl;
5818 cache_t *cacheup = *cache;
5819 clim_t *climup = *clim;
5820 met_t *met0up = *met0;
5821 met_t *met1up = *met1;
5822 atm_t *atmup = *atm;
5823#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
5824#ifdef DD
5825 dd_t *ddup = *dd;
5826#pragma acc enter data create(ddup[:1])
5827#endif
5828#endif
5829}
Air parcel data.
Definition: mptrac.h:3234
Cache data structure.
Definition: mptrac.h:3289
Climatological data.
Definition: mptrac.h:3429
Control parameters.
Definition: mptrac.h:2198
Domain decomposition data structure.
Definition: mptrac.h:3662
Meteo data structure.
Definition: mptrac.h:3488

◆ mptrac_free()

void mptrac_free ( ctl_t ctl,
cache_t cache,
clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
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.

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]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
All input pointers must point to valid allocated memory. The function assumes that the memory was allocated using compatible allocation methods.
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 5833 of file mptrac.c.

5840 {
5841
5842 /* Delete data region on GPU... */
5843#ifdef _OPENACC
5844 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY");
5845#pragma acc exit data delete(ctl,cache,clim,met0,met1,atm)
5846#ifdef DD
5847#pragma acc exit data delete(dd)
5848#endif
5849#endif
5850
5851 /* Free... */
5852 SELECT_TIMER("FREE", "MEMORY");
5853 free(atm);
5854 free(ctl);
5855 free(cache);
5856 free(clim);
5857 free(met0);
5858 free(met1);
5859
5860 /* Free MPI datatype... */
5861#ifdef DD
5862 MPI_Type_free(&dd->MPI_Particle);
5863#endif
5864 free(dd);
5865}

◆ 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 5869 of file mptrac.c.

5875 {
5876
5877 static int init;
5878
5879 met_t *mets;
5880
5881 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
5882
5883 /* Set timer... */
5884 SELECT_TIMER("GET_MET", "INPUT");
5885
5886 /* Init... */
5887 if (t == ctl->t_start || !init) {
5888 init = 1;
5889
5890 /* Read meteo data... */
5891 get_met_filename(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
5892 ctl->metbase, ctl->dt_met, filename);
5893 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5894 ERRMSG("Cannot open file!");
5895
5896 get_met_filename(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
5897 ctl->metbase, ctl->dt_met, filename);
5898 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5899 ERRMSG("Cannot open file!");
5900
5901 /* Update GPU... */
5902 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
5903 SELECT_TIMER("GET_MET", "INPUT");
5904
5905 /* Caching... */
5906 if (ctl->met_cache && t != ctl->t_stop) {
5907 get_met_filename(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
5908 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
5909 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5910 LOG(1, "Caching: %s", cachefile);
5911 if (system(cmd) != 0)
5912 WARN("Caching command failed!");
5913 }
5914 }
5915
5916 /* Read new data for forward trajectories... */
5917 if (t > (*met1)->time) {
5918
5919 /* Pointer swap... */
5920 mets = *met1;
5921 *met1 = *met0;
5922 *met0 = mets;
5923
5924 /* Read new meteo data... */
5925 get_met_filename(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
5926 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5927 ERRMSG("Cannot open file!");
5928
5929 /* Update GPU... */
5930 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
5931 SELECT_TIMER("GET_MET", "INPUT");
5932
5933 /* Caching... */
5934 if (ctl->met_cache && t != ctl->t_stop) {
5935 get_met_filename(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
5936 cachefile);
5937 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5938 LOG(1, "Caching: %s", cachefile);
5939 if (system(cmd) != 0)
5940 WARN("Caching command failed!");
5941 }
5942 }
5943
5944 /* Read new data for backward trajectories... */
5945 if (t < (*met0)->time) {
5946
5947 /* Pointer swap... */
5948 mets = *met1;
5949 *met1 = *met0;
5950 *met0 = mets;
5951
5952 /* Read new meteo data... */
5953 get_met_filename(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
5954 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5955 ERRMSG("Cannot open file!");
5956
5957 /* Update GPU... */
5958 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
5959 SELECT_TIMER("GET_MET", "INPUT");
5960
5961 /* Caching... */
5962 if (ctl->met_cache && t != ctl->t_stop) {
5963 get_met_filename(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
5964 cachefile);
5965 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5966 LOG(1, "Caching: %s", cachefile);
5967 if (system(cmd) != 0)
5968 WARN("Caching command failed!");
5969 }
5970 }
5971
5972 /* Check that grids are consistent... */
5973 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
5974 if ((*met0)->nx != (*met1)->nx
5975 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
5976 ERRMSG("Meteo grid dimensions do not match!");
5977 for (int ix = 0; ix < (*met0)->nx; ix++)
5978 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
5979 ERRMSG("Meteo grid longitudes do not match!");
5980 for (int iy = 0; iy < (*met0)->ny; iy++)
5981 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
5982 ERRMSG("Meteo grid latitudes do not match!");
5983 for (int ip = 0; ip < (*met0)->np; ip++)
5984 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
5985 ERRMSG("Meteo grid pressure levels do not match!");
5986 }
5987}
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:2583
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:7078
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2077
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2695
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2542
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,
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.
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 5991 of file mptrac.c.

5996 {
5997
5998 /* Initialize timesteps... */
5999 module_timesteps_init(ctl, atm);
6000
6001 /* Initialize random number generator... */
6002 module_rng_init(ntask);
6003
6004 /* Update GPU memory... */
6005 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
6006}
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:5543
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:5219
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 6010 of file mptrac.c.

6013 {
6014
6015 int result;
6016
6017 /* Set timer... */
6018 SELECT_TIMER("READ_ATM", "INPUT");
6019
6020 /* Init... */
6021 atm->np = 0;
6022
6023 /* Write info... */
6024 LOG(1, "Read atmospheric data: %s", filename);
6025
6026 /* Read ASCII data... */
6027 if (ctl->atm_type == 0)
6028 result = read_atm_asc(filename, ctl, atm);
6029
6030 /* Read binary data... */
6031 else if (ctl->atm_type == 1)
6032 result = read_atm_bin(filename, ctl, atm);
6033
6034 /* Read netCDF data... */
6035 else if (ctl->atm_type == 2)
6036 result = read_atm_nc(filename, ctl, atm);
6037
6038 /* Read CLaMS data... */
6039 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
6040 result = read_atm_clams(filename, ctl, atm);
6041
6042 /* Error... */
6043 else
6044 ERRMSG("Atmospheric data type not supported!");
6045
6046 /* Check result... */
6047 if (result != 1)
6048 return 0;
6049
6050 /* Check number of air parcels... */
6051 if (atm->np < 1)
6052 ERRMSG("Can not read any data!");
6053
6054 /* Write info... */
6055 double mini, maxi;
6056 LOG(2, "Number of particles: %d", atm->np);
6057 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6058 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6059 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6060 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6061 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6062 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6063 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
6064 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6065 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
6066 for (int iq = 0; iq < ctl->nq; iq++) {
6067 char msg[5 * LEN];
6068 sprintf(msg, "Quantity %s range: %s ... %s %s",
6069 ctl->qnt_name[iq], ctl->qnt_format[iq],
6070 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6071 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6072 LOG(2, msg, mini, maxi);
6073 }
6074
6075 /* Return success... */
6076 return 1;
6077}
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:7857
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:7741
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:7797
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:7699
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2217
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3000
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2214
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2208
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 6081 of file mptrac.c.

6083 {
6084
6085 /* Set timer... */
6086 SELECT_TIMER("READ_CLIM", "INPUT");
6087
6088 /* Init tropopause climatology... */
6089 clim_tropo_init(clim);
6090
6091 /* Read photolysis rates... */
6092 if (ctl->clim_photo[0] != '-')
6093 read_clim_photo(ctl->clim_photo, &clim->photo);
6094
6095 /* Read HNO3 climatology... */
6096 if (ctl->clim_hno3_filename[0] != '-')
6097 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
6098
6099 /* Read OH climatology... */
6100 if (ctl->clim_oh_filename[0] != '-') {
6101 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
6102 if (ctl->oh_chem_beta > 0)
6103 clim_oh_diurnal_correction(ctl, clim);
6104 }
6105
6106 /* Read H2O2 climatology... */
6107 if (ctl->clim_h2o2_filename[0] != '-')
6108 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
6109
6110 /* Read HO2 climatology... */
6111 if (ctl->clim_ho2_filename[0] != '-')
6112 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
6113
6114 /* Read O(1D) climatology... */
6115 if (ctl->clim_o1d_filename[0] != '-')
6116 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
6117
6118 /* Read CFC-10 time series... */
6119 if (ctl->clim_ccl4_timeseries[0] != '-')
6121
6122 /* Read CFC-11 time series... */
6123 if (ctl->clim_ccl3f_timeseries[0] != '-')
6125
6126 /* Read CFC-12 time series... */
6127 if (ctl->clim_ccl2f2_timeseries[0] != '-')
6129
6130 /* Read N2O time series... */
6131 if (ctl->clim_n2o_timeseries[0] != '-')
6132 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
6133
6134 /* Read SF6 time series... */
6135 if (ctl->clim_sf6_timeseries[0] != '-')
6136 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
6137}
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:7890
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:8009
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:8063
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:230
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:113
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2827
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2830
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2815
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2824
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2821
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2818
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 6141 of file mptrac.c.

6145 {
6146
6147 /* Set timer... */
6148 SELECT_TIMER("READ_CTL", "INPUT");
6149
6150 /* Write info... */
6151 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
6152 "(executable: %s | version: %s | compiled: %s, %s)\n",
6153 argv[0], VERSION, __DATE__, __TIME__);
6154
6155 /* Initialize quantity indices... */
6156 ctl->qnt_idx = -1;
6157 ctl->qnt_ens = -1;
6158 ctl->qnt_stat = -1;
6159 ctl->qnt_m = -1;
6160 ctl->qnt_vmr = -1;
6161 ctl->qnt_rp = -1;
6162 ctl->qnt_rhop = -1;
6163 ctl->qnt_ps = -1;
6164 ctl->qnt_ts = -1;
6165 ctl->qnt_zs = -1;
6166 ctl->qnt_us = -1;
6167 ctl->qnt_vs = -1;
6168 ctl->qnt_ess = -1;
6169 ctl->qnt_nss = -1;
6170 ctl->qnt_shf = -1;
6171 ctl->qnt_lsm = -1;
6172 ctl->qnt_sst = -1;
6173 ctl->qnt_pbl = -1;
6174 ctl->qnt_pt = -1;
6175 ctl->qnt_tt = -1;
6176 ctl->qnt_zt = -1;
6177 ctl->qnt_h2ot = -1;
6178 ctl->qnt_zg = -1;
6179 ctl->qnt_p = -1;
6180 ctl->qnt_t = -1;
6181 ctl->qnt_rho = -1;
6182 ctl->qnt_u = -1;
6183 ctl->qnt_v = -1;
6184 ctl->qnt_w = -1;
6185 ctl->qnt_h2o = -1;
6186 ctl->qnt_o3 = -1;
6187 ctl->qnt_lwc = -1;
6188 ctl->qnt_rwc = -1;
6189 ctl->qnt_iwc = -1;
6190 ctl->qnt_swc = -1;
6191 ctl->qnt_cc = -1;
6192 ctl->qnt_pct = -1;
6193 ctl->qnt_pcb = -1;
6194 ctl->qnt_cl = -1;
6195 ctl->qnt_plcl = -1;
6196 ctl->qnt_plfc = -1;
6197 ctl->qnt_pel = -1;
6198 ctl->qnt_cape = -1;
6199 ctl->qnt_cin = -1;
6200 ctl->qnt_o3c = -1;
6201 ctl->qnt_hno3 = -1;
6202 ctl->qnt_oh = -1;
6203 ctl->qnt_h2o2 = -1;
6204 ctl->qnt_ho2 = -1;
6205 ctl->qnt_o1d = -1;
6206 ctl->qnt_mloss_oh = -1;
6207 ctl->qnt_mloss_h2o2 = -1;
6208 ctl->qnt_mloss_kpp = -1;
6209 ctl->qnt_mloss_wet = -1;
6210 ctl->qnt_mloss_dry = -1;
6211 ctl->qnt_mloss_decay = -1;
6212 ctl->qnt_loss_rate = -1;
6213 ctl->qnt_psat = -1;
6214 ctl->qnt_psice = -1;
6215 ctl->qnt_pw = -1;
6216 ctl->qnt_sh = -1;
6217 ctl->qnt_rh = -1;
6218 ctl->qnt_rhice = -1;
6219 ctl->qnt_theta = -1;
6220 ctl->qnt_zeta = -1;
6221 ctl->qnt_zeta_d = -1;
6222 ctl->qnt_zeta_dot = -1;
6223 ctl->qnt_eta = -1;
6224 ctl->qnt_eta_dot = -1;
6225 ctl->qnt_tvirt = -1;
6226 ctl->qnt_lapse = -1;
6227 ctl->qnt_vh = -1;
6228 ctl->qnt_vz = -1;
6229 ctl->qnt_pv = -1;
6230 ctl->qnt_tdew = -1;
6231 ctl->qnt_tice = -1;
6232 ctl->qnt_tsts = -1;
6233 ctl->qnt_tnat = -1;
6234 ctl->qnt_Cx = -1;
6235 ctl->qnt_Ch2o = -1;
6236 ctl->qnt_Co3 = -1;
6237 ctl->qnt_Cco = -1;
6238 ctl->qnt_Coh = -1;
6239 ctl->qnt_Ch = -1;
6240 ctl->qnt_Cho2 = -1;
6241 ctl->qnt_Ch2o2 = -1;
6242 ctl->qnt_Co1d = -1;
6243 ctl->qnt_Co3p = -1;
6244 ctl->qnt_Cccl4 = -1;
6245 ctl->qnt_Cccl3f = -1;
6246 ctl->qnt_Cccl2f2 = -1;
6247 ctl->qnt_Cn2o = -1;
6248 ctl->qnt_Csf6 = -1;
6249 ctl->qnt_aoa = -1;
6250 ctl->qnt_Arn222 = -1;
6251 ctl->qnt_Apb210 = -1;
6252 ctl->qnt_Abe7 = -1;
6253 ctl->qnt_Acs137 = -1;
6254 ctl->qnt_Ai131 = -1;
6255 ctl->qnt_Axe133 = -1;
6256 ctl->qnt_subdomain = -1;
6257 ctl->qnt_destination = -1;
6258
6259 /* Read quantities... */
6260 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
6261 if (ctl->nq > NQ)
6262 ERRMSG("Too many quantities!");
6263 for (int iq = 0; iq < ctl->nq; iq++) {
6264
6265 /* Read quantity name and format... */
6266 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
6267 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
6268 ctl->qnt_longname[iq]);
6269 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
6270 ctl->qnt_format[iq]);
6271 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
6272 sprintf(ctl->qnt_format[iq], "%%.2f");
6273
6274 /* Try to identify quantity... */
6275 SET_QNT(qnt_idx, "idx", "particle index", "-")
6276 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
6277 SET_QNT(qnt_stat, "stat", "station flag", "-")
6278 SET_QNT(qnt_m, "m", "mass", "kg")
6279 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
6280 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
6281 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
6282 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
6283 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
6284 SET_QNT(qnt_zs, "zs", "surface height", "km")
6285 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
6286 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
6287 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
6288 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
6289 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
6290 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
6291 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
6292 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
6293 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
6294 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
6295 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
6296 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
6297 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
6298 SET_QNT(qnt_p, "p", "pressure", "hPa")
6299 SET_QNT(qnt_t, "t", "temperature", "K")
6300 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
6301 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
6302 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
6303 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
6304 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
6305 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
6306 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
6307 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
6308 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
6309 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
6310 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
6311 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
6312 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
6313 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
6314 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
6315 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
6316 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
6317 SET_QNT(qnt_cape, "cape", "convective available potential energy",
6318 "J/kg")
6319 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
6320 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
6321 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
6322 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
6323 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
6324 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
6325 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
6326 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
6327 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
6328 "mass loss due to H2O2 chemistry", "kg")
6329 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
6330 "kg")
6331 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
6332 "kg")
6333 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
6334 "kg")
6335 SET_QNT(qnt_mloss_decay, "mloss_decay",
6336 "mass loss due to exponential decay", "kg")
6337 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
6338 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
6339 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
6340 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
6341 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
6342 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
6343 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
6344 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
6345 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
6346 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
6347 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
6348 "K/day")
6349 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
6350 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
6351 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
6352 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
6353 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
6354 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
6355 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
6356 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
6357 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
6358 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
6359 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
6360 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
6361 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
6362 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
6363 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
6364 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
6365 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
6366 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
6367 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
6368 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
6369 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
6370 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
6371 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
6372 "ppv")
6373 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
6374 "ppv")
6375 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
6376 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
6377 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
6378 SET_QNT(qnt_Arn222, "Arn222", "Rn-222 activity", "Bq")
6379 SET_QNT(qnt_Apb210, "Apb210", "Pb-210 activity", "Bq")
6380 SET_QNT(qnt_Abe7, "Abe7", "Be-7 activity", "Bq")
6381 SET_QNT(qnt_Acs137, "Acs137", "Cs-137 activity", "Bq")
6382 SET_QNT(qnt_Ai131, "Ai131", "I-131 activity", "Bq")
6383 SET_QNT(qnt_Axe133, "Axe133", "Xe-133 activity", "Bq")
6384 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
6385 SET_QNT(qnt_destination, "destination",
6386 "subdomain index of destination", "-")
6387 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
6388 }
6389
6390 /* Vertical coordinate and velocity... */
6391 ctl->advect_vert_coord =
6392 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
6393 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
6394 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
6395
6396 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
6397 ERRMSG("Add quantity zeta for diabatic advection!");
6398 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
6399 ERRMSG("Add quantity eta for etadot avection!");
6400
6401 ctl->met_vert_coord =
6402 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
6403 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
6404 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
6405
6406 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
6407 ERRMSG
6408 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
6409 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
6410 ERRMSG
6411 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
6412
6413 /* Time steps of simulation... */
6414 ctl->direction =
6415 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
6416 if (ctl->direction != -1 && ctl->direction != 1)
6417 ERRMSG("Set DIRECTION to -1 or 1!");
6418 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
6419 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
6420
6421 /* Meteo data... */
6422 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
6423 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
6424 ctl->met_convention =
6425 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
6426 ctl->met_type =
6427 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
6428 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
6429 ERRMSG
6430 ("Please use meteo files in netcdf format for diabatic calculations.");
6431 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
6432 ERRMSG
6433 ("Please use meteo files in netcdf format for etadot calculations.");
6434 ctl->met_clams =
6435 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
6436 ctl->met_nc_scale =
6437 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
6438 ctl->met_nc_level =
6439 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
6440 ctl->met_nc_quant =
6441 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
6442 ctl->met_zstd_level =
6443 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "-3", NULL);
6444 ctl->met_zstd_nworkers =
6445 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_NWORKERS", -1, "4", NULL);
6446 ctl->met_lz4_accel =
6447 (int) scan_ctl(filename, argc, argv, "MET_LZ4_ACCEL", -1, "8", NULL);
6448 ctl->met_pck_zstd =
6449 (int) scan_ctl(filename, argc, argv, "MET_PCK_ZSTD", -1, "0", NULL);
6450 if (ctl->met_pck_zstd != 0 && ctl->met_pck_zstd != 1)
6451 ERRMSG("Set MET_PCK_ZSTD to 0 or 1!");
6452#ifndef ZSTD
6453 if (ctl->met_type == 2 && ctl->met_pck_zstd)
6454 ERRMSG("MET_PCK_ZSTD requires MPTRAC to be compiled with ZSTD support!");
6455#endif
6456 const int def_lossy_scale =
6457 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", -1, "0", NULL);
6458 for (int i = 0; i < METVAR; i++) {
6459 char defprec_zfp[LEN] = "7", deftol_zfp[LEN] = "0.0";
6460 char defprec_sz3[LEN] = "6", deftol_sz3[LEN] = "0.0";
6461 if (i == 0) { /* geopotential height */
6462 sprintf(defprec_zfp, "12");
6463 sprintf(defprec_sz3, "11");
6464 } else if (i == 1) { /* temperature */
6465 sprintf(defprec_zfp, "11");
6466 sprintf(defprec_sz3, "7");
6467 } else if (i == 2 || i == 3) { /* horizontal wind */
6468 sprintf(defprec_zfp, "7");
6469 sprintf(defprec_sz3, "7");
6470 } else if (i == 4) { /* vertical wind */
6471 sprintf(defprec_zfp, "6");
6472 sprintf(defprec_sz3, "13");
6473 } else if (i == 5) { /* potential vorticity */
6474 sprintf(defprec_zfp, "7");
6475 sprintf(defprec_sz3, "20");
6476 } else if (i == 6) { /* water vapor */
6477 sprintf(defprec_zfp, "10");
6478 sprintf(defprec_sz3, "18");
6479 } else if (i == 7) { /* ozone */
6480 sprintf(defprec_zfp, "9");
6481 sprintf(defprec_sz3, "10");
6482 } else if (i >= 8 && i <= 11) { /* cloud water fields */
6483 sprintf(defprec_zfp, "6");
6484 sprintf(defprec_sz3, "13");
6485 } else if (i == 12) { /* cloud cover */
6486 sprintf(defprec_zfp, "9");
6487 sprintf(defprec_sz3, "6");
6488 }
6489 ctl->met_zfp_prec[i] =
6490 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", i, defprec_zfp,
6491 NULL);
6492 ctl->met_zfp_tol[i] =
6493 scan_ctl(filename, argc, argv, "MET_ZFP_TOL", i, deftol_zfp, NULL);
6494 ctl->met_sz3_prec[i] =
6495 (int) scan_ctl(filename, argc, argv, "MET_SZ3_PREC", i, defprec_sz3,
6496 NULL);
6497 ctl->met_sz3_tol[i] =
6498 scan_ctl(filename, argc, argv, "MET_SZ3_TOL", i, deftol_sz3, NULL);
6499 char defscale[LEN];
6500 snprintf(defscale, LEN, "%d", def_lossy_scale);
6501 ctl->met_lossy_scale[i] =
6502 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", i, defscale,
6503 NULL);
6504 if (ctl->met_lossy_scale[i] < 0 || ctl->met_lossy_scale[i] > 1)
6505 ERRMSG("Set MET_LOSSY_SCALE to 0 or 1!");
6506 }
6507 /* Scan compression diagnostics file... */
6508 scan_ctl(filename, argc, argv, "MET_COMP_LOGFILE", -1, "-",
6509 ctl->met_comp_logfile);
6510 ctl->met_cms_batch =
6511 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
6512 ctl->met_cms_zstd =
6513 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
6514 ctl->met_cms_nd0x =
6515 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
6516 ctl->met_cms_nd0y =
6517 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
6518 ctl->met_cms_maxlev =
6519 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
6520 for (int i = 0; i < METVAR; i++) {
6521 char defeps[LEN] = "1.0";
6522 if (i == 1 || i == 2 || i == 3)
6523 sprintf(defeps, "0.05");
6524 ctl->met_cms_eps[i] =
6525 scan_ctl(filename, argc, argv, "MET_CMS_EPS", i, defeps, NULL);
6526 }
6527 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
6528 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
6529 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
6530 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
6531 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
6532 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
6533 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
6534 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
6535 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
6536 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
6537 ctl->met_detrend =
6538 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
6539 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
6540 if (ctl->met_np > EP)
6541 ERRMSG("Too many pressure levels!");
6542 ctl->met_press_level_def =
6543 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
6544 NULL);
6545 if (ctl->met_press_level_def >= 0) {
6546 level_definitions(ctl);
6547 } else {
6548 if (ctl->met_np > 0) {
6549 for (int ip = 0; ip < ctl->met_np; ip++)
6550 ctl->met_p[ip] =
6551 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
6552 }
6553 }
6554 ctl->met_nlev =
6555 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
6556 if (ctl->met_nlev > EP)
6557 ERRMSG("Too many model levels!");
6558 for (int ip = 0; ip < ctl->met_nlev; ip++)
6559 ctl->met_lev_hyam[ip] =
6560 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
6561 for (int ip = 0; ip < ctl->met_nlev; ip++)
6562 ctl->met_lev_hybm[ip] =
6563 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
6564 ctl->met_geopot_sx =
6565 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
6566 ctl->met_geopot_sy =
6567 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
6568 ctl->met_relhum =
6569 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
6570 ctl->met_cape =
6571 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
6572 if (ctl->met_cape < 0 || ctl->met_cape > 1)
6573 ERRMSG("Set MET_CAPE to 0 or 1!");
6574 ctl->met_pbl =
6575 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
6576 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
6577 ERRMSG("Set MET_PBL to 0 ... 3!");
6578 ctl->met_pbl_min =
6579 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
6580 ctl->met_pbl_max =
6581 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
6582 ctl->met_tropo =
6583 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
6584 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
6585 ERRMSG("Set MET_TROPO to 0 ... 5!");
6586 ctl->met_tropo_pv =
6587 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
6588 ctl->met_tropo_theta =
6589 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
6590 ctl->met_tropo_spline =
6591 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
6592 ctl->met_dt_out =
6593 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
6594 ctl->met_cache =
6595 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
6596 ctl->met_mpi_share =
6597 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
6598
6599 /* Sorting... */
6600 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
6601
6602 /* Isosurface parameters... */
6603 ctl->isosurf =
6604 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
6605 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
6606
6607 /* Random number generator... */
6608 ctl->rng_type =
6609 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
6610 if (ctl->rng_type < 0 || ctl->rng_type > 2)
6611 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
6612
6613 /* Advection parameters... */
6614 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
6615 if (!
6616 (ctl->advect == 0 || ctl->advect == 1 || ctl->advect == 2
6617 || ctl->advect == 4))
6618 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
6619
6620 /* Diffusion parameters... */
6621 ctl->diffusion
6622 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
6623 if (ctl->diffusion < 0 || ctl->diffusion > 2)
6624 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
6625 ctl->turb_dx_pbl =
6626 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
6627 ctl->turb_dx_trop =
6628 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
6629 ctl->turb_dx_strat =
6630 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
6631 ctl->turb_dz_pbl =
6632 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
6633 ctl->turb_dz_trop =
6634 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
6635 ctl->turb_dz_strat =
6636 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
6637 ctl->turb_mesox =
6638 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
6639 ctl->turb_mesoz =
6640 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
6641
6642 /* Convection... */
6643 ctl->conv_mix_pbl
6644 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
6645 ctl->conv_pbl_trans
6646 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
6647 ctl->conv_cape
6648 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
6649 ctl->conv_cin
6650 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
6651 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
6652
6653 /* Boundary conditions... */
6654 ctl->bound_mass =
6655 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
6656 ctl->bound_mass_trend =
6657 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
6658 ctl->bound_vmr =
6659 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
6660 ctl->bound_vmr_trend =
6661 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
6662 ctl->bound_lat0 =
6663 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
6664 ctl->bound_lat1 =
6665 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
6666 ctl->bound_p0 =
6667 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
6668 ctl->bound_p1 =
6669 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
6670 ctl->bound_dps =
6671 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
6672 ctl->bound_dzs =
6673 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
6674 ctl->bound_zetas =
6675 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
6676 ctl->bound_pbl =
6677 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
6678
6679 /* Species parameters... */
6680 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
6681 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
6682 ctl->molmass = 120.907;
6683 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
6684 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
6685 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
6686 ctl->molmass = 137.359;
6687 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
6688 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
6689 } else if (strcasecmp(ctl->species, "CH4") == 0) {
6690 ctl->molmass = 16.043;
6691 ctl->oh_chem_reaction = 2;
6692 ctl->oh_chem[0] = 2.45e-12;
6693 ctl->oh_chem[1] = 1775;
6694 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
6695 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6696 } else if (strcasecmp(ctl->species, "CO") == 0) {
6697 ctl->molmass = 28.01;
6698 ctl->oh_chem_reaction = 3;
6699 ctl->oh_chem[0] = 6.9e-33;
6700 ctl->oh_chem[1] = 2.1;
6701 ctl->oh_chem[2] = 1.1e-12;
6702 ctl->oh_chem[3] = -1.3;
6703 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
6704 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
6705 } else if (strcasecmp(ctl->species, "CO2") == 0) {
6706 ctl->molmass = 44.009;
6707 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
6708 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6709 } else if (strcasecmp(ctl->species, "H2O") == 0) {
6710 ctl->molmass = 18.01528;
6711 } else if (strcasecmp(ctl->species, "N2O") == 0) {
6712 ctl->molmass = 44.013;
6713 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
6714 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
6715 } else if (strcasecmp(ctl->species, "NH3") == 0) {
6716 ctl->molmass = 17.031;
6717 ctl->oh_chem_reaction = 2;
6718 ctl->oh_chem[0] = 1.7e-12;
6719 ctl->oh_chem[1] = 710;
6720 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
6721 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
6722 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
6723 ctl->molmass = 63.012;
6724 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
6725 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
6726 } else if (strcasecmp(ctl->species, "NO") == 0) {
6727 ctl->molmass = 30.006;
6728 ctl->oh_chem_reaction = 3;
6729 ctl->oh_chem[0] = 7.1e-31;
6730 ctl->oh_chem[1] = 2.6;
6731 ctl->oh_chem[2] = 3.6e-11;
6732 ctl->oh_chem[3] = 0.1;
6733 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
6734 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6735 } else if (strcasecmp(ctl->species, "NO2") == 0) {
6736 ctl->molmass = 46.005;
6737 ctl->oh_chem_reaction = 3;
6738 ctl->oh_chem[0] = 1.8e-30;
6739 ctl->oh_chem[1] = 3.0;
6740 ctl->oh_chem[2] = 2.8e-11;
6741 ctl->oh_chem[3] = 0.0;
6742 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
6743 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6744 } else if (strcasecmp(ctl->species, "O3") == 0) {
6745 ctl->molmass = 47.997;
6746 ctl->oh_chem_reaction = 2;
6747 ctl->oh_chem[0] = 1.7e-12;
6748 ctl->oh_chem[1] = 940;
6749 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
6750 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
6751 } else if (strcasecmp(ctl->species, "SF6") == 0) {
6752 ctl->molmass = 146.048;
6753 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
6754 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
6755 } else if (strcasecmp(ctl->species, "SO2") == 0) {
6756 ctl->molmass = 64.066;
6757 ctl->oh_chem_reaction = 3;
6758 ctl->oh_chem[0] = 2.9e-31;
6759 ctl->oh_chem[1] = 4.1;
6760 ctl->oh_chem[2] = 1.7e-12;
6761 ctl->oh_chem[3] = -0.2;
6762 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
6763 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
6764 }
6765
6766 /* Molar mass... */
6767 char defstr[LEN];
6768 sprintf(defstr, "%g", ctl->molmass);
6769 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
6770
6771 /* OH chemistry... */
6772 sprintf(defstr, "%d", ctl->oh_chem_reaction);
6773 ctl->oh_chem_reaction =
6774 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
6775 NULL);
6776 for (int ip = 0; ip < 4; ip++) {
6777 sprintf(defstr, "%g", ctl->oh_chem[ip]);
6778 ctl->oh_chem[ip] =
6779 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
6780 }
6781 ctl->oh_chem_beta =
6782 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
6783
6784 /* H2O2 chemistry... */
6785 ctl->h2o2_chem_reaction =
6786 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
6787
6788 /* KPP chemistry... */
6789 ctl->kpp_chem =
6790 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
6791 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
6792
6793 /* First order tracer chemistry... */
6794 ctl->tracer_chem =
6795 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
6796
6797 /* Radioactive decay... */
6798 ctl->radio_decay =
6799 (int) scan_ctl(filename, argc, argv, "RADIO_DECAY", -1, "0", NULL);
6800
6801 /* Wet deposition... */
6802 for (int ip = 0; ip < 2; ip++) {
6803 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
6804 ctl->wet_depo_ic_h[ip] =
6805 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
6806 }
6807 for (int ip = 0; ip < 1; ip++) {
6808 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
6809 ctl->wet_depo_bc_h[ip] =
6810 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
6811 }
6812 ctl->wet_depo_so2_ph =
6813 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
6814 ctl->wet_depo_ic_a =
6815 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
6816 ctl->wet_depo_ic_b =
6817 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
6818 ctl->wet_depo_bc_a =
6819 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
6820 ctl->wet_depo_bc_b =
6821 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
6822 ctl->wet_depo_pre[0] =
6823 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
6824 ctl->wet_depo_pre[1] =
6825 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
6827 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
6829 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
6830
6831 /* Dry deposition... */
6832 ctl->dry_depo_vdep =
6833 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
6834 ctl->dry_depo_dp =
6835 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
6836
6837 /* Climatological data... */
6838 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
6839 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
6840 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
6841 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
6842 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
6843 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
6844 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
6845 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
6846 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
6847 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
6848 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
6849 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
6850 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
6851 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
6852 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
6853 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
6854 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
6855 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
6856 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
6857 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
6858 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
6859 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
6860
6861 /* Mixing... */
6862 ctl->mixing_dt =
6863 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
6864 ctl->mixing_trop =
6865 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
6866 ctl->mixing_strat =
6867 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
6868 ctl->mixing_z0 =
6869 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
6870 ctl->mixing_z1 =
6871 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
6872 ctl->mixing_nz =
6873 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
6874 ctl->mixing_lon0 =
6875 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
6876 ctl->mixing_lon1 =
6877 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
6878 ctl->mixing_nx =
6879 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
6880 ctl->mixing_lat0 =
6881 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
6882 ctl->mixing_lat1 =
6883 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
6884 ctl->mixing_ny =
6885 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
6886
6887 /* Chemistry grid... */
6888 ctl->chemgrid_z0 =
6889 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
6890 ctl->chemgrid_z1 =
6891 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
6892 ctl->chemgrid_nz =
6893 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
6894 ctl->chemgrid_lon0 =
6895 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
6896 ctl->chemgrid_lon1 =
6897 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
6898 ctl->chemgrid_nx =
6899 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
6900 ctl->chemgrid_lat0 =
6901 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
6902 ctl->chemgrid_lat1 =
6903 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
6904 ctl->chemgrid_ny =
6905 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
6906
6907 /* Exponential decay... */
6908 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
6909 ctl->tdec_strat =
6910 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
6911
6912 /* PSC analysis... */
6913 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
6914 ctl->psc_hno3 =
6915 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
6916
6917 /* Output of atmospheric data... */
6918 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
6919 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
6920 ctl->atm_dt_out =
6921 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
6922 ctl->atm_filter =
6923 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
6924 ctl->atm_stride =
6925 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
6926 ctl->atm_type =
6927 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
6928 ctl->atm_type_out =
6929 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
6930 if (ctl->atm_type_out == -1)
6931 ctl->atm_type_out = ctl->atm_type;
6932 ctl->atm_nc_level =
6933 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
6934 for (int iq = 0; iq < ctl->nq; iq++)
6935 ctl->atm_nc_quant[iq] =
6936 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
6937 ctl->obs_type =
6938 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
6939
6940 /* Output of CSI data... */
6941 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
6942 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
6943 ctl->csi_dt_out =
6944 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
6945 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
6946 ctl->csi_obsmin =
6947 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
6948 ctl->csi_modmin =
6949 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
6950 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
6951 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
6952 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
6953 ctl->csi_lon0 =
6954 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
6955 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
6956 ctl->csi_nx =
6957 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
6958 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
6959 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
6960 ctl->csi_ny =
6961 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
6962
6963 /* Output of ensemble data... */
6964 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
6965 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
6966 ctl->ens_dt_out =
6967 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
6968
6969 /* Output of grid data... */
6970 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
6971 ctl->grid_basename);
6972 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
6973 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
6974 ctl->grid_dt_out =
6975 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
6976 ctl->grid_sparse =
6977 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
6978 ctl->grid_nc_level =
6979 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
6980 for (int iq = 0; iq < ctl->nq; iq++)
6981 ctl->grid_nc_quant[iq] =
6982 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
6983 ctl->grid_stddev =
6984 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
6985 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
6986 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
6987 ctl->grid_nz =
6988 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
6989 ctl->grid_lon0 =
6990 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
6991 ctl->grid_lon1 =
6992 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
6993 ctl->grid_nx =
6994 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
6995 ctl->grid_lat0 =
6996 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
6997 ctl->grid_lat1 =
6998 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
6999 ctl->grid_ny =
7000 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
7001 ctl->grid_type =
7002 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
7003
7004 /* Output of profile data... */
7005 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
7006 ctl->prof_basename);
7007 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
7008 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
7009 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
7010 ctl->prof_nz =
7011 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
7012 ctl->prof_lon0 =
7013 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
7014 ctl->prof_lon1 =
7015 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
7016 ctl->prof_nx =
7017 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
7018 ctl->prof_lat0 =
7019 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
7020 ctl->prof_lat1 =
7021 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
7022 ctl->prof_ny =
7023 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
7024
7025 /* Output of sample data... */
7026 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
7027 ctl->sample_basename);
7028 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
7029 ctl->sample_kernel);
7030 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
7031 ctl->sample_obsfile);
7032 ctl->sample_dx =
7033 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
7034 ctl->sample_dz =
7035 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
7036
7037 /* Output of station data... */
7038 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
7039 ctl->stat_basename);
7040 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
7041 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
7042 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
7043 ctl->stat_t0 =
7044 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
7045 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
7046
7047 /* Output of VTK data... */
7048 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
7049 ctl->vtk_dt_out =
7050 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
7051 ctl->vtk_stride =
7052 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
7053 ctl->vtk_scale =
7054 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
7055 ctl->vtk_offset =
7056 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
7057 ctl->vtk_sphere =
7058 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
7059
7060 /* Domain decomposition... */
7061 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
7063 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
7064 (ctl->dd == 1) ? "2" : "1", NULL);
7065 ctl->dd_subdomains_zonal =
7066 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
7067 (ctl->dd == 1) ? "2" : "1", NULL);
7069 ctl->dd = 1;
7070 else if (ctl->dd == 1)
7071 ERRMSG("Please provide zonal and meridional subdomain numbers!");
7072 ctl->dd_halos_size =
7073 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
7074}
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:3264
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:11683
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:354
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:364
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1707
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3098
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2310
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3059
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3026
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2343
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3035
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2289
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3222
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2987
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2322
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3029
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2331
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3050
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2298
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3176
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2705
double stat_r
Search radius around station [km].
Definition: mptrac.h:3182
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3053
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3206
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2673
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2319
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2397
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3125
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3101
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2625
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2692
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2361
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2433
char species[LEN]
Species.
Definition: mptrac.h:2803
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3044
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3056
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2670
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2313
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3086
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3104
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3116
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2244
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2340
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3107
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2367
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2689
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3161
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2427
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2661
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3077
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2265
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2409
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3188
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3020
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3122
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3047
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2271
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3092
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2394
int radio_decay
Switch for radioactive decay module (0=off, 1=on).
Definition: mptrac.h:2935
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2658
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2631
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2241
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3128
int met_pck_zstd
Apply an additional ZSTD compression step to PCK payloads (0=off, 1=on).
Definition: mptrac.h:2580
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2247
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3131
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3023
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2667
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3032
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2628
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3074
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3134
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2304
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2683
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3140
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2226
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2698
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2436
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2364
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3041
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3185
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3213
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3005
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2607
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2649
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2929
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3017
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2262
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2253
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3194
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2764
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3164
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2355
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3071
char met_comp_logfile[LEN]
Filename for per-level compression diagnostics ("-" disables output).
Definition: mptrac.h:2598
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2283
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2403
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2676
int met_dx
Stride for longitudes.
Definition: mptrac.h:2619
int qnt_destination
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2523
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2415
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2932
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2725
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2286
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3203
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2301
double met_zfp_tol[METVAR]
ZFP compression tolerance.
Definition: mptrac.h:2586
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2358
int met_sz3_prec[METVAR]
SZ3 compression precision.
Definition: mptrac.h:2589
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2307
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3149
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2406
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2295
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3170
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3014
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3089
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2250
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3110
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2984
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2274
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2334
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3137
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2652
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2292
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:2993
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2926
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3065
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3038
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2430
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3179
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3113
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2637
double met_cms_eps[METVAR]
cmultiscale compression epsilon.
Definition: mptrac.h:2616
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2346
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2610
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2352
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3095
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2259
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3068
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3158
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:2996
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2664
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2990
int met_lossy_scale[METVAR]
Apply levelwise [0,1] scaling before lossy compression (0=off, 1=on).
Definition: mptrac.h:2595
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3155
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2601
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2974
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2634
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3143
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2328
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2376
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2391
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2655
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3152
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2349
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2977
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3146
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2923
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3011
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2604
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2613
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3083
double met_sz3_tol[METVAR]
SZ3 compression tolerance.
Definition: mptrac.h:2592
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3191
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2277
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2851
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3200
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2439
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2268
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3008
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2400
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2256
int met_dy
Stride for latitudes.
Definition: mptrac.h:2622
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3216
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2220
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2686
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2316
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2211
int met_zfp_prec[METVAR]
ZFP compression precision.
Definition: mptrac.h:2583
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3167
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3197
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3173
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3119
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3219
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2280
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2325
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2337
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3080
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2442
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 7078 of file mptrac.c.

7083 {
7084
7085 /* Write info... */
7086 LOG(1, "Read meteo data: %s", filename);
7087
7088 /* Set rank... */
7089 int rank = 0;
7090#ifdef MPI
7091 if (ctl->met_mpi_share)
7092 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
7093#endif
7094
7095 /* Check rank... */
7096 if (!ctl->met_mpi_share || rank == 0) {
7097
7098 /* Read netCDF data... */
7099 if (ctl->met_type == 0) {
7100 if (read_met_nc(filename, ctl, met, dd) != 1)
7101 return 0;
7102 }
7103
7104 /* Read binary data... */
7105 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
7106 || ctl->met_type == 7 || ctl->met_type == 8) {
7107 if (read_met_bin(filename, ctl, met) != 1)
7108 return 0;
7109 }
7110#ifdef ECCODES
7111 /* Read grib data... */
7112 else if (ctl->met_type == 6) {
7113 if (read_met_grib(filename, ctl, met) != 1)
7114 return 0;
7115 }
7116#endif
7117
7118 /* Not implemented... */
7119 else
7120 ERRMSG("MET_TYPE not implemented!");
7121
7122 /* Preprocessing for netCDF and grib files... */
7123 if (ctl->met_type == 0 || ctl->met_type == 6) {
7124
7125 /* Extrapolate data for lower boundary... */
7127
7128 /* Fix polar winds... */
7130
7131 /* Create periodic boundary conditions... */
7132#ifndef DD
7133 read_met_periodic(met);
7134#endif
7135
7136 /* Downsampling... */
7137 read_met_sample(ctl, met);
7138
7139 /* Calculate geopotential heights... */
7140 read_met_geopot(ctl, met);
7141
7142 /* Calculate potential vorticity... */
7143 read_met_pv(met);
7144
7145 /* Calculate boundary layer data... */
7146 read_met_pbl(ctl, met);
7147
7148 /* Calculate tropopause data... */
7149 read_met_tropo(ctl, clim, met);
7150
7151 /* Calculate cloud properties... */
7152 read_met_cloud(met);
7153
7154 /* Calculate convective available potential energy... */
7155 read_met_cape(ctl, clim, met);
7156
7157 /* Calculate total column ozone... */
7158 read_met_ozone(met);
7159
7160 /* Detrending... */
7161 read_met_detrend(ctl, met);
7162
7163 /* Check meteo data and smooth zeta profiles ... */
7164 read_met_monotonize(ctl, met);
7165 }
7166 }
7167
7168 /* Broadcast data via MPI... */
7169#ifdef MPI
7170 if (ctl->met_mpi_share) {
7171
7172 /* Set timer... */
7173 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM");
7174 LOG(2, "Broadcast data on rank %d...", rank);
7175
7176 /* Broadcast... */
7177 broadcast_large_data(met, sizeof(met_t));
7178 }
7179#endif
7180
7181 /* Return success... */
7182 return 1;
7183}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:8818
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:8778
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:11237
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:8617
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:10845
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:8674
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:10544
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:10982
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:10629
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:11208
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:11102
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:8203
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:11043
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:8502
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,
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.
tCurrent simulation time in seconds.
ddMPI information required for the domain decomposition.
Author
Lars Hoffmann

Definition at line 7187 of file mptrac.c.

7195 {
7196
7197 /* Initialize modules... */
7198 if (t == ctl->t_start) {
7199
7200 /* Initialize isosurface data... */
7201 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7202 module_isosurf_init(ctl, cache, *met0, *met1, atm);
7203
7204 /* Initialize advection... */
7205 module_advect_init(ctl, cache, *met0, *met1, atm);
7206
7207 /* Initialize chemistry... */
7208 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
7209 }
7210
7211 /* Set time steps of air parcels... */
7212 module_timesteps(ctl, cache, *met0, atm, t);
7213
7214 /* Sort particles... */
7215 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
7216 module_sort(ctl, *met0, atm);
7217
7218 /* Check positions (initial)... */
7219 module_position(cache, *met0, *met1, atm);
7220
7221 /* Advection... */
7222 if (ctl->advect > 0)
7223 module_advect(ctl, cache, *met0, *met1, atm);
7224
7225 /* Turbulent diffusion... */
7226 if (ctl->diffusion == 1
7227 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
7228 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
7229 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
7230 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
7231
7232 /* Mesoscale diffusion... */
7233 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
7234 module_diff_meso(ctl, cache, *met0, *met1, atm);
7235
7236 /* Diffusion... */
7237 if (ctl->diffusion == 2)
7238 module_diff_pbl(ctl, cache, *met0, *met1, atm);
7239
7240 /* Convection... */
7241 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
7242 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
7243 module_convection(ctl, cache, *met0, *met1, atm);
7244
7245 /* Sedimentation... */
7246 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
7247 module_sedi(ctl, cache, *met0, *met1, atm);
7248
7249 /* Isosurface... */
7250 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7251 module_isosurf(ctl, cache, *met0, *met1, atm);
7252
7253 /* Check positions (final)... */
7254 module_position(cache, *met0, *met1, atm);
7255
7256 /* Interpolate meteo data... */
7257 if (ctl->met_dt_out > 0
7258 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
7259 module_meteo(ctl, cache, clim, *met0, *met1, atm);
7260
7261 /* Check boundary conditions (initial)... */
7262 if ((ctl->bound_lat0 < ctl->bound_lat1)
7263 && (ctl->bound_p0 > ctl->bound_p1))
7264 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
7265
7266 /* Initialize quantity of total loss rate... */
7267 if (ctl->qnt_loss_rate >= 0) {
7268 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
7269 atm->q[ctl->qnt_loss_rate][ip] = 0;
7270 }
7271 }
7272
7273 /* Decay of particle mass... */
7274 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
7275 module_decay(ctl, cache, clim, atm);
7276
7277 /* Interparcel mixing... */
7278 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
7279 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
7280 module_mixing(ctl, clim, atm, t);
7281
7282 /* Calculate the tracer vmr in the chemistry grid... */
7283 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
7284 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
7285 module_chem_grid(ctl, *met0, *met1, atm, t);
7286
7287 /* OH chemistry... */
7288 if (ctl->oh_chem_reaction != 0)
7289 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
7290
7291 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
7292 if (ctl->h2o2_chem_reaction != 0)
7293 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
7294
7295 /* First-order tracer chemistry... */
7296 if (ctl->tracer_chem)
7297 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
7298
7299 /* Radioactive decay... */
7300 if (ctl->radio_decay)
7301 module_radio_decay(ctl, cache, atm);
7302
7303 /* Domain decomposition... */
7304 if (ctl->dd) {
7305#ifdef DD
7306 module_dd(ctl, cache, dd, atm, met0);
7307#else
7308 ERRMSG("Code was compiled without DD!");
7309
7310 /* This will never execute, hack to avoid compilation error... */
7311 LOG(3, "%d", dd->nx_glob);
7312#endif
7313 }
7314
7315 /* KPP chemistry... */
7316 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
7317#ifdef KPP
7318 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
7319#else
7320 ERRMSG("Code was compiled without KPP!");
7321#endif
7322 }
7323
7324 /* Wet deposition... */
7325 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
7326 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
7327 module_wet_depo(ctl, cache, *met0, *met1, atm);
7328
7329 /* Dry deposition... */
7330 if (ctl->dry_depo_vdep > 0)
7331 module_dry_depo(ctl, cache, *met0, *met1, atm);
7332
7333 /* Check boundary conditions (final)... */
7334 if ((ctl->bound_lat0 < ctl->bound_lat1)
7335 && (ctl->bound_p0 > ctl->bound_p1))
7336 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
7337}
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:3520
void module_timesteps(const ctl_t *ctl, cache_t *cache, met_t *met0, atm_t *atm, const double t)
Calculate time steps for air parcels based on specified conditions.
Definition: mptrac.c:5496
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:4745
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:4131
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:3968
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:4852
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:4569
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:5645
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:3806
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:5355
void module_sort(const ctl_t *ctl, const met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:5384
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:4010
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:3710
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:3683
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:5161
void module_position(const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Update the positions and pressure levels of atmospheric particles.
Definition: mptrac.c:5110
void module_diff_meso(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate mesoscale diffusion for atmospheric particles.
Definition: mptrac.c:4170
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:4372
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:5574
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:4487
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:4247
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:4639
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:5026
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:4424
void module_dd(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.
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.
int nx_glob
Number of global longitudes.
Definition: mptrac.h:3669
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 7341 of file mptrac.c.

7347 {
7348
7349 /* Update GPU... */
7350 if (ctl != NULL) {
7351#ifdef _OPENACC
7352 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7353#pragma acc update device(ctl[:1])
7354#endif
7355 }
7356
7357 if (cache != NULL) {
7358#ifdef _OPENACC
7359 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7360#pragma acc update device(cache[:1])
7361#endif
7362 }
7363
7364 if (clim != NULL) {
7365#ifdef _OPENACC
7366 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7367#pragma acc update device(clim[:1])
7368#endif
7369 }
7370
7371 if (met0 != NULL) {
7372#ifdef _OPENACC
7373 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7374 met_t *met0up = *met0;
7375#pragma acc update device(met0up[:1])
7376#endif
7377 }
7378
7379 if (met1 != NULL) {
7380#ifdef _OPENACC
7381 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7382 met_t *met1up = *met1;
7383#pragma acc update device(met1up[:1])
7384#endif
7385 }
7386
7387 if (atm != NULL) {
7388#ifdef _OPENACC
7389 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7390#pragma acc update device(atm[:1])
7391#endif
7392 }
7393}

◆ 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 7397 of file mptrac.c.

7403 {
7404
7405 /* Update GPU... */
7406 if (ctl != NULL) {
7407#ifdef _OPENACC
7408 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7409#pragma acc update host(ctl[:1])
7410#endif
7411 }
7412
7413 if (cache != NULL) {
7414#ifdef _OPENACC
7415 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7416#pragma acc update host(cache[:1])
7417#endif
7418 }
7419
7420 if (clim != NULL) {
7421#ifdef _OPENACC
7422 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7423#pragma acc update host(clim[:1])
7424#endif
7425 }
7426
7427 if (met0 != NULL) {
7428#ifdef _OPENACC
7429 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7430 met_t *met0up = *met0;
7431#pragma acc update host(met0up[:1])
7432#endif
7433 }
7434
7435 if (met1 != NULL) {
7436#ifdef _OPENACC
7437 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7438 met_t *met1up = *met1;
7439#pragma acc update host(met1up[:1])
7440#endif
7441 }
7442
7443 if (atm != NULL) {
7444#ifdef _OPENACC
7445 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7446#pragma acc update host(atm[:1])
7447#endif
7448 }
7449}

◆ 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 7453 of file mptrac.c.

7457 {
7458
7459 /* Set timer... */
7460 SELECT_TIMER("WRITE_ATM", "OUTPUT");
7461
7462 /* Write info... */
7463 LOG(1, "Write atmospheric data: %s", filename);
7464
7465 /* Write ASCII data... */
7466 if (ctl->atm_type_out == 0)
7467 write_atm_asc(filename, ctl, atm, t);
7468
7469 /* Write binary data... */
7470 else if (ctl->atm_type_out == 1)
7471 write_atm_bin(filename, ctl, atm);
7472
7473 /* Write netCDF data... */
7474 else if (ctl->atm_type_out == 2)
7475 write_atm_nc(filename, ctl, atm);
7476
7477 /* Write CLaMS trajectory data... */
7478 else if (ctl->atm_type_out == 3)
7479 write_atm_clams_traj(filename, ctl, atm, t);
7480
7481 /* Write CLaMS pos data... */
7482 else if (ctl->atm_type_out == 4)
7483 write_atm_clams(filename, ctl, atm);
7484
7485 /* Error... */
7486 else
7487 ERRMSG("Atmospheric data type not supported!");
7488
7489 /* Write info... */
7490 double mini, maxi;
7491 LOG(2, "Number of particles: %d", atm->np);
7492 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
7493 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
7494 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
7495 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
7496 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
7497 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
7498 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
7499 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
7500 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
7501 for (int iq = 0; iq < ctl->nq; iq++) {
7502 char msg[5 * LEN];
7503 sprintf(msg, "Quantity %s range: %s ... %s %s",
7504 ctl->qnt_name[iq], ctl->qnt_format[iq],
7505 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
7506 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
7507 LOG(2, msg, mini, maxi);
7508 }
7509}
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:12198
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:12013
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:12145
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:12095
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:12356
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 7513 of file mptrac.c.

7516 {
7517
7518 /* Set timer... */
7519 SELECT_TIMER("WRITE_MET", "OUTPUT");
7520
7521 /* Write info... */
7522 LOG(1, "Write meteo data: %s", filename);
7523
7524 /* Check compression flags... */
7525#ifndef ZFP
7526 if (ctl->met_type == 3)
7527 ERRMSG("MPTRAC was compiled without ZFP compression!");
7528#endif
7529#ifndef ZSTD
7530 if (ctl->met_type == 4)
7531 ERRMSG("MPTRAC was compiled without ZSTD compression!");
7532#endif
7533#ifndef LZ4
7534 if (ctl->met_type == 8)
7535 ERRMSG("MPTRAC was compiled without LZ4 compression!");
7536#endif
7537#ifndef CMS
7538 if (ctl->met_type == 5)
7539 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
7540#endif
7541#ifndef SZ3
7542 if (ctl->met_type == 7)
7543 ERRMSG("MPTRAC was compiled without SZ3 compression!");
7544#endif
7545
7546 /* Write netCDF data... */
7547 if (ctl->met_type == 0)
7548 write_met_nc(filename, ctl, met);
7549
7550 /* Write binary data... */
7551 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
7552 || ctl->met_type == 7 || ctl->met_type == 8)
7553 write_met_bin(filename, ctl, met);
7554
7555 /* Not implemented... */
7556 else
7557 ERRMSG("MET_TYPE not implemented!");
7558}
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:13447
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:13202
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,
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.
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 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 7562 of file mptrac.c.

7568 {
7569
7570 char ext[10], filename[2 * LEN];
7571
7572 double r;
7573
7574 int year, mon, day, hour, min, sec;
7575
7576 /* Get time... */
7577 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
7578
7579 /* Update host... */
7580 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
7581 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
7582 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
7583 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
7584 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
7585 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
7586 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
7587
7588 /* Write atmospheric data... */
7589 if (ctl->atm_basename[0] != '-' &&
7590 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
7591 if (ctl->atm_type_out == 0)
7592 sprintf(ext, "tab");
7593 else if (ctl->atm_type_out == 1)
7594 sprintf(ext, "bin");
7595 else if (ctl->atm_type_out == 2)
7596 sprintf(ext, "nc");
7597 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
7598 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
7599 mptrac_write_atm(filename, ctl, atm, t);
7600 }
7601
7602 /* Write gridded data... */
7603 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
7604 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
7605 dirname, ctl->grid_basename, year, mon, day, hour, min,
7606 ctl->grid_type == 0 ? "tab" : "nc");
7607 write_grid(filename, ctl, met0, met1, atm, t);
7608 }
7609
7610 /* Write CSI data... */
7611 if (ctl->csi_basename[0] != '-') {
7612 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
7613 write_csi(filename, ctl, atm, t);
7614 }
7615
7616 /* Write ensemble data... */
7617 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
7618 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
7619 dirname, ctl->ens_basename, year, mon, day, hour, min);
7620 write_ens(filename, ctl, atm, t);
7621 }
7622
7623 /* Write profile data... */
7624 if (ctl->prof_basename[0] != '-') {
7625 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
7626 write_prof(filename, ctl, met0, met1, atm, t);
7627 }
7628
7629 /* Write sample data... */
7630 if (ctl->sample_basename[0] != '-') {
7631 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
7632 write_sample(filename, ctl, met0, met1, atm, t);
7633 }
7634
7635 /* Write station data... */
7636 if (ctl->stat_basename[0] != '-') {
7637 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
7638 write_station(filename, ctl, atm, t);
7639 }
7640
7641 /* Write VTK data... */
7642 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
7643 static int nvtk;
7644 if (t == ctl->t_start)
7645 nvtk = 0;
7646 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
7647 write_vtk(filename, ctl, atm, t);
7648 }
7649}
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:7453
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:12680
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:13672
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:7397
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:14061
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:14147
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:13899
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:12777
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:12405
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 7653 of file mptrac.c.

7656 {
7657
7658 /* Check water vapor volume mixing ratio... */
7659 const double h2o_help = MAX(h2o, 0.1e-6);
7660
7661 /* Calculate T_NAT... */
7662 const double p_hno3 = hno3 * p / 1.333224;
7663 const double p_h2o = h2o_help * p / 1.333224;
7664 const double a = 0.009179 - 0.00088 * log10(p_h2o);
7665 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
7666 const double c = -11397.0 / a;
7667 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
7668 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
7669 if (x2 > 0)
7670 tnat = x2;
7671
7672 return tnat;
7673}

◆ 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 and ps.

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 7677 of file mptrac.c.

7682 {
7683
7684 /* Get pressure range... */
7685 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
7686 const double p0 = pbl;
7687
7688 /* Get weighting factor... */
7689 if (atm->p[ip] > p0)
7690 return 1;
7691 else if (atm->p[ip] < p1)
7692 return 0;
7693 else
7694 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
7695}

◆ 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 7699 of file mptrac.c.

7702 {
7703
7704 /* Open file... */
7705 FILE *in;
7706 if (!(in = fopen(filename, "r"))) {
7707 WARN("Cannot open file!");
7708 return 0;
7709 }
7710
7711 /* Read line... */
7712 char line[LEN];
7713 while (fgets(line, LEN, in)) {
7714
7715 /* Read data... */
7716 char *tok;
7717 TOK(line, tok, "%lg", atm->time[atm->np]);
7718 TOK(NULL, tok, "%lg", atm->p[atm->np]);
7719 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
7720 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
7721 for (int iq = 0; iq < ctl->nq; iq++)
7722 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
7723
7724 /* Convert altitude to pressure... */
7725 atm->p[atm->np] = P(atm->p[atm->np]);
7726
7727 /* Increment data point counter... */
7728 if ((++atm->np) > NP)
7729 ERRMSG("Too many data points!");
7730 }
7731
7732 /* Close file... */
7733 fclose(in);
7734
7735 /* Return success... */
7736 return 1;
7737}
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1878

◆ 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 7741 of file mptrac.c.

7744 {
7745
7746 /* Open file... */
7747 FILE *in;
7748 if (!(in = fopen(filename, "r")))
7749 return 0;
7750
7751 /* Check version of binary data... */
7752 int version;
7753 FREAD(&version, int,
7754 1,
7755 in);
7756 if (version != 100)
7757 ERRMSG("Wrong version of binary data!");
7758
7759 /* Read data... */
7760 FREAD(&atm->np, int,
7761 1,
7762 in);
7763 FREAD(atm->time, double,
7764 (size_t) atm->np,
7765 in);
7766 FREAD(atm->p, double,
7767 (size_t) atm->np,
7768 in);
7769 FREAD(atm->lon, double,
7770 (size_t) atm->np,
7771 in);
7772 FREAD(atm->lat, double,
7773 (size_t) atm->np,
7774 in);
7775 for (int iq = 0; iq < ctl->nq; iq++)
7776 FREAD(atm->q[iq], double,
7777 (size_t) atm->np,
7778 in);
7779
7780 /* Read final flag... */
7781 int final;
7782 FREAD(&final, int,
7783 1,
7784 in);
7785 if (final != 999)
7786 ERRMSG("Error while reading binary data!");
7787
7788 /* Close file... */
7789 fclose(in);
7790
7791 /* Return success... */
7792 return 1;
7793}

◆ 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 7797 of file mptrac.c.

7800 {
7801
7802 int ncid, varid;
7803
7804 /* Open file... */
7805 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7806 return 0;
7807
7808 /* Get dimensions... */
7809 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
7810
7811 /* Get time... */
7812 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
7813 NC(nc_get_var_double(ncid, varid, atm->time));
7814 } else {
7815 WARN("TIME_INIT not found use time instead!");
7816 double time_init;
7817 NC_GET_DOUBLE("time", &time_init, 1);
7818 for (int ip = 0; ip < atm->np; ip++) {
7819 atm->time[ip] = time_init;
7820 }
7821 }
7822
7823 /* Read zeta coordinate, pressure is optional... */
7824 if (ctl->advect_vert_coord == 1) {
7825 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
7826 NC_GET_DOUBLE("PRESS", atm->p, 0);
7827 }
7828
7829 /* Read pressure, zeta coordinate is optional... */
7830 else {
7831 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
7832 NC(nc_get_var_double(ncid, varid, atm->p));
7833 } else {
7834 WARN("PRESS_INIT not found use PRESS instead!");
7835 nc_inq_varid(ncid, "PRESS", &varid);
7836 NC(nc_get_var_double(ncid, varid, atm->p));
7837 }
7838 }
7839
7840 /* Read further quantities if requested... */
7841 for (int iq = 0; iq < ctl->nq; iq++)
7842 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7843
7844 /* Read longitude and latitude... */
7845 NC_GET_DOUBLE("LON", atm->lon, 1);
7846 NC_GET_DOUBLE("LAT", atm->lat, 1);
7847
7848 /* Close file... */
7849 NC(nc_close(ncid));
7850
7851 /* Return success... */
7852 return 1;
7853}
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1212
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1271
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1301

◆ 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 7857 of file mptrac.c.

7860 {
7861
7862 int ncid, varid;
7863
7864 /* Open file... */
7865 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7866 return 0;
7867
7868 /* Get dimensions... */
7869 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
7870
7871 /* Read geolocations... */
7872 NC_GET_DOUBLE("time", atm->time, 1);
7873 NC_GET_DOUBLE("press", atm->p, 1);
7874 NC_GET_DOUBLE("lon", atm->lon, 1);
7875 NC_GET_DOUBLE("lat", atm->lat, 1);
7876
7877 /* Read variables... */
7878 for (int iq = 0; iq < ctl->nq; iq++)
7879 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7880
7881 /* Close file... */
7882 NC(nc_close(ncid));
7883
7884 /* Return success... */
7885 return 1;
7886}

◆ 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 7890 of file mptrac.c.

7892 {
7893
7894 int ncid, varid;
7895
7896 /* Write info... */
7897 LOG(1, "Read photolysis rates: %s", filename);
7898
7899 /* Open netCDF file... */
7900 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7901 WARN("Photolysis rate data are missing!");
7902 return;
7903 }
7904
7905 /* Read pressure data... */
7906 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
7907 NC_GET_DOUBLE("press", photo->p, 1);
7908 if (photo->p[0] < photo->p[1])
7909 ERRMSG("Pressure data are not descending!");
7910
7911 /* Read total column ozone data... */
7912 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
7913 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
7914 if (photo->o3c[0] > photo->o3c[1])
7915 ERRMSG("Total column ozone data are not ascending!");
7916
7917 /* Read solar zenith angle data... */
7918 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
7919 NC_GET_DOUBLE("sza", photo->sza, 1);
7920 if (photo->sza[0] > photo->sza[1])
7921 ERRMSG("Solar zenith angle data are not ascending!");
7922
7923 /* Read data... */
7924 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
7925 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
7926 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
7927 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
7928 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
7929 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
7930 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
7931 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
7932 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
7933
7934 /* Close netCDF file... */
7935 NC(nc_close(ncid));
7936
7937 /* Write info... */
7938 LOG(2, "Number of pressure levels: %d", photo->np);
7939 LOG(2, "Altitude levels: %g, %g ... %g km",
7940 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
7941 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7942 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
7943 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
7944 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
7945 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
7946 RAD2DEG(photo->sza[photo->nsza - 1]));
7947 LOG(2, "Number of total column ozone values: %d", photo->no3c);
7948 LOG(2, "Total column ozone: %g, %g ... %g DU",
7949 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
7950 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
7951 photo->n2o[0][0][0], photo->n2o[1][0][0],
7952 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7953 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
7954 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
7955 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7956 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
7957 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
7958 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7959 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
7960 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
7961 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7962 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
7963 photo->o2[0][0][0], photo->o2[1][0][0],
7964 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7965 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
7966 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
7967 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7968 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
7969 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
7970 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7971 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
7972 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
7973 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7974 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
7975 photo->h2o[0][0][0], photo->h2o[1][0][0],
7976 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7977}
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:7981
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:399
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:394
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:404
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3357
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3354
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3363
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3366
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3360
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 7981 of file mptrac.c.

7985 {
7986
7987 /* Allocate... */
7988 double *help;
7989 ALLOC(help, double,
7990 photo->np * photo->nsza * photo->no3c);
7991
7992 /* Read varible... */
7993 int varid;
7994 NC_GET_DOUBLE(varname, help, 1);
7995
7996 /* Copy data... */
7997 for (int ip = 0; ip < photo->np; ip++)
7998 for (int is = 0; is < photo->nsza; is++)
7999 for (int io = 0; io < photo->no3c; io++)
8000 var[ip][is][io] =
8001 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
8002
8003 /* Free... */
8004 free(help);
8005}

◆ 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 8009 of file mptrac.c.

8011 {
8012
8013 /* Write info... */
8014 LOG(1, "Read climatological time series: %s", filename);
8015
8016 /* Open file... */
8017 FILE *in;
8018 if (!(in = fopen(filename, "r"))) {
8019 WARN("Cannot open file!");
8020 return 0;
8021 }
8022
8023 /* Read data... */
8024 char line[LEN];
8025 int nh = 0;
8026 while (fgets(line, LEN, in))
8027 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
8028
8029 /* Convert years to seconds... */
8030 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
8031
8032 /* Check data... */
8033 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
8034 ERRMSG("Time series must be ascending!");
8035
8036 /* Count time steps... */
8037 if ((++nh) >= CTS)
8038 ERRMSG("Too many data points!");
8039 }
8040
8041 /* Close file... */
8042 fclose(in);
8043
8044 /* Check number of data points... */
8045 ts->ntime = nh;
8046 if (nh < 2)
8047 ERRMSG("Not enough data points!");
8048
8049 /* Write info... */
8050 LOG(2, "Number of time steps: %d", ts->ntime);
8051 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
8052 ts->time[nh - 1]);
8053 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
8054 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
8055 (size_t) nh));
8056
8057 /* Exit success... */
8058 return 1;
8059}
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:414

◆ 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 8063 of file mptrac.c.

8066 {
8067
8068 int ncid, varid, it, iy, iz, iz2, nt;
8069
8070 double *help, varmin = 1e99, varmax = -1e99;
8071
8072 /* Write info... */
8073 LOG(1, "Read %s data: %s", varname, filename);
8074
8075 /* Open netCDF file... */
8076 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8077 WARN("%s climatology data are missing!", varname);
8078 return;
8079 }
8080
8081 /* Read pressure data... */
8082 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
8083 NC_GET_DOUBLE("press", zm->p, 1);
8084 if (zm->p[0] < zm->p[1])
8085 ERRMSG("Pressure data are not descending!");
8086
8087 /* Read latitudes... */
8088 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
8089 NC_GET_DOUBLE("lat", zm->lat, 1);
8090 if (zm->lat[0] > zm->lat[1])
8091 ERRMSG("Latitude data are not ascending!");
8092
8093 /* Set time data (for monthly means)... */
8094 zm->ntime = 12;
8095 zm->time[0] = 1209600.00;
8096 zm->time[1] = 3888000.00;
8097 zm->time[2] = 6393600.00;
8098 zm->time[3] = 9072000.00;
8099 zm->time[4] = 11664000.00;
8100 zm->time[5] = 14342400.00;
8101 zm->time[6] = 16934400.00;
8102 zm->time[7] = 19612800.00;
8103 zm->time[8] = 22291200.00;
8104 zm->time[9] = 24883200.00;
8105 zm->time[10] = 27561600.00;
8106 zm->time[11] = 30153600.00;
8107
8108 /* Check number of timesteps... */
8109 NC_INQ_DIM("time", &nt, 12, 12, 1);
8110
8111 /* Read data... */
8112 ALLOC(help, double,
8113 zm->nlat * zm->np * zm->ntime);
8114 NC_GET_DOUBLE(varname, help, 1);
8115 for (it = 0; it < zm->ntime; it++)
8116 for (iz = 0; iz < zm->np; iz++)
8117 for (iy = 0; iy < zm->nlat; iy++)
8118 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
8119 free(help);
8120
8121 /* Fix data gaps... */
8122 for (it = 0; it < zm->ntime; it++)
8123 for (iy = 0; iy < zm->nlat; iy++)
8124 for (iz = 0; iz < zm->np; iz++) {
8125 if (zm->vmr[it][iz][iy] < 0) {
8126 for (iz2 = 0; iz2 < zm->np; iz2++)
8127 if (zm->vmr[it][iz2][iy] >= 0) {
8128 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8129 break;
8130 }
8131 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
8132 if (zm->vmr[it][iz2][iy] >= 0) {
8133 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8134 break;
8135 }
8136 }
8137 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
8138 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
8139 }
8140
8141 /* Close netCDF file... */
8142 NC(nc_close(ncid));
8143
8144 /* Write info... */
8145 LOG(2, "Number of time steps: %d", zm->ntime);
8146 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
8147 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
8148 LOG(2, "Number of pressure levels: %d", zm->np);
8149 LOG(2, "Altitude levels: %g, %g ... %g km",
8150 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
8151 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
8152 zm->p[1], zm->p[zm->np - 1]);
8153 LOG(2, "Number of latitudes: %d", zm->nlat);
8154 LOG(2, "Latitudes: %g, %g ... %g deg",
8155 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
8156 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
8157 varmax);
8158}
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:389

◆ 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 8162 of file mptrac.c.

8166 {
8167
8168 /* Write info... */
8169 LOG(1, "Read kernel function: %s", filename);
8170
8171 /* Open file... */
8172 FILE *in;
8173 if (!(in = fopen(filename, "r")))
8174 ERRMSG("Cannot open file!");
8175
8176 /* Read data... */
8177 char line[LEN];
8178 int n = 0;
8179 while (fgets(line, LEN, in))
8180 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
8181 if (n > 0 && kz[n] < kz[n - 1])
8182 ERRMSG("Height levels must be ascending!");
8183 if ((++n) >= EP)
8184 ERRMSG("Too many height levels!");
8185 }
8186
8187 /* Close file... */
8188 fclose(in);
8189
8190 /* Check number of data points... */
8191 *nk = n;
8192 if (n < 2)
8193 ERRMSG("Not enough height levels!");
8194
8195 /* Normalize kernel function... */
8196 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
8197 for (int iz = 0; iz < n; iz++)
8198 kw[iz] /= kmax;
8199}

◆ 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 8203 of file mptrac.c.

8206 {
8207
8208 FILE *in;
8209
8210 double r;
8211
8212 int year, mon, day, hour, min, sec;
8213
8214 /* Set timer... */
8215 SELECT_TIMER("READ_MET_BIN", "INPUT");
8216
8217 /* Open file... */
8218 if (!(in = fopen(filename, "r"))) {
8219 WARN("Cannot open file!");
8220 return 0;
8221 }
8222
8223 /* Check type of binary data... */
8224 int met_type;
8225 FREAD(&met_type, int,
8226 1,
8227 in);
8228 if (met_type != ctl->met_type)
8229 ERRMSG("Wrong MET_TYPE of binary data!");
8230
8231 /* Check version of binary data... */
8232 int version;
8233 FREAD(&version, int,
8234 1,
8235 in);
8236 if (version != 104)
8237 ERRMSG("Wrong version of binary data!");
8238
8239 /* Read time... */
8240 FREAD(&met->time, double,
8241 1,
8242 in);
8243 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8244 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8245 met->time, year, mon, day, hour, min);
8246 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8247 || day < 1 || day > 31 || hour < 0 || hour > 23)
8248 ERRMSG("Error while reading time!");
8249
8250 /* Read dimensions... */
8251 FREAD(&met->nx, int,
8252 1,
8253 in);
8254 LOG(2, "Number of longitudes: %d", met->nx);
8255 if (met->nx < 2 || met->nx > EX)
8256 ERRMSG("Number of longitudes out of range!");
8257
8258 FREAD(&met->ny, int,
8259 1,
8260 in);
8261 LOG(2, "Number of latitudes: %d", met->ny);
8262 if (met->ny < 2 || met->ny > EY)
8263 ERRMSG("Number of latitudes out of range!");
8264
8265 FREAD(&met->np, int,
8266 1,
8267 in);
8268 LOG(2, "Number of levels: %d", met->np);
8269 if (met->np < 2 || met->np > EP)
8270 ERRMSG("Number of levels out of range!");
8271
8272 /* Read grid... */
8273 FREAD(met->lon, double,
8274 (size_t) met->nx,
8275 in);
8276 LOG(2, "Longitudes: %g, %g ... %g deg",
8277 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
8278
8279 FREAD(met->lat, double,
8280 (size_t) met->ny,
8281 in);
8282 LOG(2, "Latitudes: %g, %g ... %g deg",
8283 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
8284
8285 FREAD(met->p, double,
8286 (size_t) met->np,
8287 in);
8288 LOG(2, "Altitude levels: %g, %g ... %g km",
8289 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8290 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8291 met->p[0], met->p[1], met->p[met->np - 1]);
8292
8293 /* Read surface data... */
8294 read_met_bin_2d(in, met, met->ps, "PS");
8295 read_met_bin_2d(in, met, met->ts, "TS");
8296 read_met_bin_2d(in, met, met->zs, "ZS");
8297 read_met_bin_2d(in, met, met->us, "US");
8298 read_met_bin_2d(in, met, met->vs, "VS");
8299 read_met_bin_2d(in, met, met->ess, "ESS");
8300 read_met_bin_2d(in, met, met->nss, "NSS");
8301 read_met_bin_2d(in, met, met->shf, "SHF");
8302 read_met_bin_2d(in, met, met->lsm, "LSM");
8303 read_met_bin_2d(in, met, met->sst, "SST");
8304 read_met_bin_2d(in, met, met->pbl, "PBL");
8305 read_met_bin_2d(in, met, met->pt, "PT");
8306 read_met_bin_2d(in, met, met->tt, "TT");
8307 read_met_bin_2d(in, met, met->zt, "ZT");
8308 read_met_bin_2d(in, met, met->h2ot, "H2OT");
8309 read_met_bin_2d(in, met, met->pct, "PCT");
8310 read_met_bin_2d(in, met, met->pcb, "PCB");
8311 read_met_bin_2d(in, met, met->cl, "CL");
8312 read_met_bin_2d(in, met, met->plcl, "PLCL");
8313 read_met_bin_2d(in, met, met->plfc, "PLFC");
8314 read_met_bin_2d(in, met, met->pel, "PEL");
8315 read_met_bin_2d(in, met, met->cape, "CAPE");
8316 read_met_bin_2d(in, met, met->cin, "CIN");
8317 read_met_bin_2d(in, met, met->o3c, "O3C");
8318
8319 /* Read level data... */
8320 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
8321 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
8322 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
8323 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
8324 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
8325 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
8326 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
8327 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
8328 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
8329 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
8330 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
8331 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
8332 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
8333
8334 /* Read final flag... */
8335 int final;
8336 FREAD(&final, int,
8337 1,
8338 in);
8339 if (final != 999)
8340 ERRMSG("Error while reading binary data!");
8341
8342 /* Close file... */
8343 fclose(in);
8344
8345 /* Return success... */
8346 return 1;
8347}
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:8351
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:8380
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:344
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3566
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3554
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3626
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3596
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3590
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3572
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3548
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3623
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3536
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3635
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3530
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3542
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3575
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3587
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3593
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3581
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3563
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3557
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3539
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3551
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3629
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3569
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3614
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3578
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3545
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3584
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3632
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 8351 of file mptrac.c.

8355 {
8356
8357 float *help;
8358
8359 /* Allocate... */
8360 ALLOC(help, float,
8361 EX * EY);
8362
8363 /* Read uncompressed... */
8364 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
8365 FREAD(help, float,
8366 (size_t) (met->nx * met->ny),
8367 in);
8368
8369 /* Copy data... */
8370 for (int ix = 0; ix < met->nx; ix++)
8371 for (int iy = 0; iy < met->ny; iy++)
8372 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
8373
8374 /* Free... */
8375 free(help);
8376}
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:480

◆ 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 8380 of file mptrac.c.

8387 {
8388
8389 float *help;
8390 const int metvar = compress_metvar_index(varname);
8391 (void) metvar;
8392
8393 /* Allocate... */
8394 ALLOC(help, float,
8395 EX * EY * EP);
8396
8397 /* Read uncompressed data... */
8398 if (ctl->met_type == 1) {
8399 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
8400 FREAD(help, float,
8401 (size_t) (met->nx * met->ny * met->np),
8402 in);
8403 }
8404
8405 /* Read packed data... */
8406 else if (ctl->met_type == 2)
8407 compress_pck(varname, help, (size_t) (met->ny * met->nx),
8408 (size_t) met->np, met->p, 1, ctl->met_pck_zstd,
8409 ctl->met_zstd_level, ctl->met_zstd_nworkers, NULL, in);
8410
8411 /* Read ZFP data... */
8412 else if (ctl->met_type == 3) {
8413#ifdef ZFP
8414 int precision;
8415 FREAD(&precision, int,
8416 1,
8417 in);
8418
8419 double tolerance;
8420 FREAD(&tolerance, double,
8421 1,
8422 in);
8423
8424 compress_zfp(varname, help, met->np, met->ny, met->nx, met->p,
8425 precision, tolerance, ctl->met_lossy_scale[metvar], 1, NULL,
8426 in);
8427#else
8428 ERRMSG("MPTRAC was compiled without ZFP compression!");
8429#endif
8430 }
8431
8432 /* Read zstd data... */
8433 else if (ctl->met_type == 4) {
8434#ifdef ZSTD
8435 compress_zstd(varname, help, (size_t) (met->ny * met->nx),
8436 (size_t) met->np, met->p, 1, ctl->met_zstd_level,
8437 ctl->met_zstd_nworkers, NULL, in);
8438#else
8439 ERRMSG("MPTRAC was compiled without ZSTD compression!");
8440#endif
8441 }
8442
8443 /* Read LZ4 data... */
8444 else if (ctl->met_type == 8) {
8445#ifdef LZ4
8446 compress_lz4(varname, help, (size_t) (met->ny * met->nx),
8447 (size_t) met->np, met->p, 1, ctl->met_lz4_accel, NULL, in);
8448#else
8449 ERRMSG("MPTRAC was compiled without LZ4 compression!");
8450#endif
8451 }
8452
8453 /* Read cmultiscale data... */
8454 else if (ctl->met_type == 5) {
8455#ifdef CMS
8456 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
8457 (size_t) met->np, met->p, 1, NULL, in);
8458#else
8459 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
8460#endif
8461 }
8462
8463 /* Read SZ3 data... */
8464 else if (ctl->met_type == 7) {
8465#ifdef SZ3
8466 int precision;
8467 FREAD(&precision, int,
8468 1,
8469 in);
8470
8471 double tolerance;
8472 FREAD(&tolerance, double,
8473 1,
8474 in);
8475
8476 compress_sz3(varname, help, met->np, met->ny, met->nx, met->p,
8477 precision, tolerance, ctl->met_lossy_scale[metvar], 1, NULL,
8478 in);
8479#else
8480 ERRMSG("MPTRAC was compiled without sz3 compression!");
8481#endif
8482 }
8483
8484 /* Copy data... */
8485#pragma omp parallel for default(shared) collapse(2)
8486 for (int ix = 0; ix < met->nx; ix++)
8487 for (int iy = 0; iy < met->ny; iy++)
8488 for (int ip = 0; ip < met->np; ip++) {
8489 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
8490 if (var[ix][iy][ip] < bound_min)
8491 var[ix][iy][ip] = bound_min;
8492 else if (var[ix][iy][ip] > bound_max)
8493 var[ix][iy][ip] = bound_max;
8494 }
8495
8496 /* Free... */
8497 free(help);
8498}
void compress_pck(const char *varname, float *array, const size_t nxy, const size_t nz, const double *plev, const int decompress, const int pck_zstd, const int zstd_level, const int zstd_nworkers, FILE *level_log, FILE *inout)
Compresses or decompresses a 3D array of floats.
Definition: mptrac.c:993
int compress_metvar_index(const char *varname)
Maps a meteorological variable name to its internal MPTRAC variable index.
Definition: mptrac.c:957
void compress_cms(const ctl_t *ctl, const char *varname, float *array, const size_t nx, const size_t ny, const size_t np, const double *plev, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3-D meteorological field using cmultiscale.
void compress_sz3(const char *varname, float *array, const int nx, const int ny, const int nz, const double *plev, const int precision, const double tolerance, const int lossy_scale, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3-D float array using the SZ3 library.
void compress_zstd(const char *varname, float *array, const size_t nxy, const size_t nz, const double *plev, const int decompress, const int level, const int nworkers, FILE *level_log, FILE *inout)
Compresses or decompresses a float array using Zstandard (ZSTD).
void compress_lz4(const char *varname, float *array, const size_t nxy, const size_t nz, const double *plev, const int decompress, const int acceleration, FILE *level_log, FILE *inout)
Compresses or decompresses a float array using LZ4.
void compress_zfp(const char *varname, float *array, const int nx, const int ny, const int nz, const double *plev, const int precision, const double tolerance, const int lossy_scale, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
int met_zstd_nworkers
ZSTD number of worker threads (0=single-threaded, default=4).
Definition: mptrac.h:2574
int met_zstd_level
ZSTD compression level (from -5 to 22, default=-3).
Definition: mptrac.h:2571
int met_lz4_accel
LZ4 acceleration factor (>=1, default=8).
Definition: mptrac.h:2577
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 8502 of file mptrac.c.

8505 {
8506
8507 /* Check parameters... */
8508 if (ctl->met_cape != 1)
8509 return;
8510
8511 /* Set timer... */
8512 SELECT_TIMER("READ_MET_CAPE", "METPROC");
8513 LOG(2, "Calculate CAPE...");
8514
8515 /* Vertical spacing (about 100 m)... */
8516 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
8517
8518 /* Loop over columns... */
8519#pragma omp parallel for default(shared) collapse(2)
8520 for (int ix = 0; ix < met->nx; ix++)
8521 for (int iy = 0; iy < met->ny; iy++) {
8522
8523 /* Get potential temperature and water vapor at lowest 50 hPa... */
8524 int n = 0;
8525 double h2o = 0, t, theta = 0;
8526 double pbot = MIN(met->ps[ix][iy], met->p[0]);
8527 double ptop = pbot - 50.;
8528 for (int ip = 0; ip < met->np; ip++) {
8529 if (met->p[ip] <= pbot) {
8530 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
8531 h2o += met->h2o[ix][iy][ip];
8532 n++;
8533 }
8534 if (met->p[ip] < ptop && n > 0)
8535 break;
8536 }
8537 theta /= n;
8538 h2o /= n;
8539
8540 /* Cannot compute anything if water vapor is missing... */
8541 met->plcl[ix][iy] = NAN;
8542 met->plfc[ix][iy] = NAN;
8543 met->pel[ix][iy] = NAN;
8544 met->cape[ix][iy] = NAN;
8545 met->cin[ix][iy] = NAN;
8546 if (h2o <= 0)
8547 continue;
8548
8549 /* Find lifted condensation level (LCL)... */
8550 ptop = P(20.);
8551 pbot = met->ps[ix][iy];
8552 do {
8553 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
8554 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
8555 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
8556 ptop = met->plcl[ix][iy];
8557 else
8558 pbot = met->plcl[ix][iy];
8559 } while (pbot - ptop > 0.1);
8560
8561 /* Calculate CIN up to LCL... */
8563 double dcape, dz, h2o_env, t_env;
8564 double p = met->ps[ix][iy];
8565 met->cape[ix][iy] = met->cin[ix][iy] = 0;
8566 do {
8567 dz = dz0 * TVIRT(t, h2o);
8568 p /= pfac;
8569 t = theta / pow(1000. / p, 0.286);
8570 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
8571 &t_env, ci, cw, 1);
8572 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
8573 &h2o_env, ci, cw, 0);
8574 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
8575 TVIRT(t_env, h2o_env) * dz;
8576 if (dcape < 0)
8577 met->cin[ix][iy] += fabsf((float) dcape);
8578 } while (p > met->plcl[ix][iy]);
8579
8580 /* Calculate level of free convection (LFC), equilibrium level (EL),
8581 and convective available potential energy (CAPE)... */
8582 dcape = 0;
8583 p = met->plcl[ix][iy];
8584 t = theta / pow(1000. / p, 0.286);
8585 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
8586 do {
8587 dz = dz0 * TVIRT(t, h2o);
8588 p /= pfac;
8589 t -= lapse_rate(t, h2o) * dz;
8590 double psat = PSAT(t);
8591 h2o = psat / (p - (1. - EPS) * psat);
8592 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
8593 &t_env, ci, cw, 1);
8594 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
8595 &h2o_env, ci, cw, 0);
8596 double dcape_old = dcape;
8597 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
8598 TVIRT(t_env, h2o_env) * dz;
8599 if (dcape > 0) {
8600 met->cape[ix][iy] += (float) dcape;
8601 if (!isfinite(met->plfc[ix][iy]))
8602 met->plfc[ix][iy] = (float) p;
8603 } else if (dcape_old > 0)
8604 met->pel[ix][iy] = (float) p;
8605 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
8606 met->cin[ix][iy] += fabsf((float) dcape);
8607 } while (p > ptop);
8608
8609 /* Check results... */
8610 if (!isfinite(met->plfc[ix][iy]))
8611 met->cin[ix][iy] = NAN;
8612 }
8613}
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:202
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 8617 of file mptrac.c.

8618 {
8619
8620 /* Set timer... */
8621 SELECT_TIMER("READ_MET_CLOUD", "METPROC");
8622 LOG(2, "Calculate cloud data...");
8623
8624 /* Thresholds for cloud detection... */
8625 const double ccmin = 0.01, cwmin = 1e-6;
8626
8627 /* Loop over columns... */
8628#pragma omp parallel for default(shared) collapse(2)
8629 for (int ix = 0; ix < met->nx; ix++)
8630 for (int iy = 0; iy < met->ny; iy++) {
8631
8632 /* Init... */
8633 met->pct[ix][iy] = NAN;
8634 met->pcb[ix][iy] = NAN;
8635 met->cl[ix][iy] = 0;
8636
8637 /* Loop over pressure levels... */
8638 for (int ip = 0; ip < met->np - 1; ip++) {
8639
8640 /* Check pressure... */
8641 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
8642 continue;
8643
8644 /* Check ice water and liquid water content... */
8645 if (met->cc[ix][iy][ip] > ccmin
8646 && (met->lwc[ix][iy][ip] > cwmin
8647 || met->rwc[ix][iy][ip] > cwmin
8648 || met->iwc[ix][iy][ip] > cwmin
8649 || met->swc[ix][iy][ip] > cwmin)) {
8650
8651 /* Get cloud top pressure ... */
8652 met->pct[ix][iy]
8653 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
8654
8655 /* Get cloud bottom pressure ... */
8656 if (!isfinite(met->pcb[ix][iy]))
8657 met->pcb[ix][iy]
8658 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
8659 }
8660
8661 /* Get cloud water... */
8662 met->cl[ix][iy] += (float)
8663 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
8664 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
8665 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
8666 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
8667 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
8668 }
8669 }
8670}

◆ 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 8674 of file mptrac.c.

8676 {
8677
8678 met_t *help;
8679
8680 /* Check parameters... */
8681 if (ctl->met_detrend <= 0)
8682 return;
8683
8684 /* Set timer... */
8685 SELECT_TIMER("READ_MET_DETREND", "METPROC");
8686 LOG(2, "Detrend meteo data...");
8687
8688 /* Allocate... */
8689 ALLOC(help, met_t, 1);
8690
8691 /* Calculate standard deviation... */
8692 const double sigma = ctl->met_detrend / 2.355;
8693 const double tssq = 2. * SQR(sigma);
8694
8695 /* Calculate box size in latitude... */
8696 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
8697 sy = MIN(MAX(1, sy), met->ny / 2);
8698
8699 /* Calculate background... */
8700#pragma omp parallel for default(shared) collapse(2)
8701 for (int ix = 0; ix < met->nx; ix++) {
8702 for (int iy = 0; iy < met->ny; iy++) {
8703
8704 /* Calculate Cartesian coordinates... */
8705 double x0[3];
8706 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
8707
8708 /* Calculate box size in longitude... */
8709 int sx =
8710 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
8711 fabs(met->lon[1] - met->lon[0]));
8712 sx = MIN(MAX(1, sx), met->nx / 2);
8713
8714 /* Init... */
8715 float wsum = 0;
8716 for (int ip = 0; ip < met->np; ip++) {
8717 help->t[ix][iy][ip] = 0;
8718 help->u[ix][iy][ip] = 0;
8719 help->v[ix][iy][ip] = 0;
8720 help->w[ix][iy][ip] = 0;
8721 }
8722
8723 /* Loop over neighboring grid points... */
8724 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
8725 int ix3 = ix2;
8726 if (ix3 < 0)
8727 ix3 += met->nx;
8728 else if (ix3 >= met->nx)
8729 ix3 -= met->nx;
8730 for (int iy2 = MAX(iy - sy, 0);
8731 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
8732
8733 /* Calculate Cartesian coordinates... */
8734 double x1[3];
8735 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
8736
8737 /* Calculate weighting factor... */
8738 const float w = (float) exp(-DIST2(x0, x1) / tssq);
8739
8740 /* Add data... */
8741 wsum += w;
8742 for (int ip = 0; ip < met->np; ip++) {
8743 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
8744 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
8745 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
8746 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
8747 }
8748 }
8749 }
8750
8751 /* Normalize... */
8752 for (int ip = 0; ip < met->np; ip++) {
8753 help->t[ix][iy][ip] /= wsum;
8754 help->u[ix][iy][ip] /= wsum;
8755 help->v[ix][iy][ip] /= wsum;
8756 help->w[ix][iy][ip] /= wsum;
8757 }
8758 }
8759 }
8760
8761 /* Subtract background... */
8762#pragma omp parallel for default(shared) collapse(3)
8763 for (int ix = 0; ix < met->nx; ix++)
8764 for (int iy = 0; iy < met->ny; iy++)
8765 for (int ip = 0; ip < met->np; ip++) {
8766 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
8767 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
8768 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
8769 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
8770 }
8771
8772 /* Free... */
8773 free(help);
8774}
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:2565
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:724
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 8778 of file mptrac.c.

8779 {
8780
8781 /* Set timer... */
8782 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC");
8783 LOG(2, "Extrapolate meteo data...");
8784
8785 /* Loop over columns... */
8786#pragma omp parallel for default(shared) collapse(2)
8787 for (int ix = 0; ix < met->nx; ix++)
8788 for (int iy = 0; iy < met->ny; iy++) {
8789
8790 /* Find lowest valid data point... */
8791 int ip0;
8792 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
8793 if (!isfinite(met->t[ix][iy][ip0])
8794 || !isfinite(met->u[ix][iy][ip0])
8795 || !isfinite(met->v[ix][iy][ip0])
8796 || !isfinite(met->w[ix][iy][ip0]))
8797 break;
8798
8799 /* Extrapolate... */
8800 for (int ip = ip0; ip >= 0; ip--) {
8801 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
8802 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
8803 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
8804 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
8805 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
8806 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
8807 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
8808 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
8809 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
8810 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
8811 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
8812 }
8813 }
8814}

◆ 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 8818 of file mptrac.c.

8820 {
8821
8822 float *help;
8823
8824 double logp[EP];
8825
8826 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
8827
8828 /* Set timer... */
8829 SELECT_TIMER("READ_MET_GEOPOT", "METPROC");
8830 LOG(2, "Calculate geopotential heights...");
8831
8832 /* Allocate... */
8833 ALLOC(help, float,
8834 EX * EY * EP);
8835
8836 /* Calculate log pressure... */
8837#pragma omp parallel for default(shared)
8838 for (int ip = 0; ip < met->np; ip++)
8839 logp[ip] = log(met->p[ip]);
8840
8841 /* Apply hydrostatic equation to calculate geopotential heights... */
8842#pragma omp parallel for default(shared) collapse(2)
8843 for (int ix = 0; ix < met->nx; ix++)
8844 for (int iy = 0; iy < met->ny; iy++) {
8845
8846 /* Get surface height and pressure... */
8847 const double zs = met->zs[ix][iy];
8848 const double lnps = log(met->ps[ix][iy]);
8849
8850 /* Get temperature and water vapor at the surface... */
8851 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
8852 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
8853 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
8854 const double h2os =
8855 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
8856 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
8857
8858 /* Upper part of profile... */
8859 met->z[ix][iy][ip0 + 1]
8860 = (float) (zs +
8861 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
8862 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
8863 for (int ip = ip0 + 2; ip < met->np; ip++)
8864 met->z[ix][iy][ip]
8865 = (float) (met->z[ix][iy][ip - 1] +
8866 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
8867 met->h2o[ix][iy][ip - 1], logp[ip],
8868 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8869
8870 /* Lower part of profile... */
8871 met->z[ix][iy][ip0]
8872 = (float) (zs +
8873 ZDIFF(lnps, ts, h2os, logp[ip0],
8874 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
8875 for (int ip = ip0 - 1; ip >= 0; ip--)
8876 met->z[ix][iy][ip]
8877 = (float) (met->z[ix][iy][ip + 1] +
8878 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
8879 met->h2o[ix][iy][ip + 1], logp[ip],
8880 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8881 }
8882
8883 /* Check control parameters... */
8884 if (dx == 0 || dy == 0)
8885 return;
8886
8887 /* Default smoothing parameters... */
8888 if (dx < 0 || dy < 0) {
8889 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
8890 dx = 3;
8891 dy = 2;
8892 } else {
8893 dx = 6;
8894 dy = 4;
8895 }
8896 }
8897
8898 /* Calculate weights for smoothing... */
8899 float ws[dx + 1][dy + 1];
8900#pragma omp parallel for default(shared) collapse(2)
8901 for (int ix = 0; ix <= dx; ix++)
8902 for (int iy = 0; iy < dy; iy++)
8903 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
8904 * (1.0f - (float) iy / (float) dy);
8905
8906 /* Copy data... */
8907#pragma omp parallel for default(shared) collapse(3)
8908 for (int ix = 0; ix < met->nx; ix++)
8909 for (int iy = 0; iy < met->ny; iy++)
8910 for (int ip = 0; ip < met->np; ip++)
8911 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
8912
8913 /* Horizontal smoothing... */
8914#pragma omp parallel for default(shared) collapse(3)
8915 for (int ip = 0; ip < met->np; ip++)
8916 for (int ix = 0; ix < met->nx; ix++)
8917 for (int iy = 0; iy < met->ny; iy++) {
8918 float res = 0, wsum = 0;
8919 int iy0 = MAX(iy - dy + 1, 0);
8920 int iy1 = MIN(iy + dy - 1, met->ny - 1);
8921 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
8922 int ix3 = ix2;
8923 if (ix3 < 0)
8924 ix3 += met->nx;
8925 else if (ix3 >= met->nx)
8926 ix3 -= met->nx;
8927 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
8928 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
8929 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
8930 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
8931 wsum += w;
8932 }
8933 }
8934 if (wsum > 0)
8935 met->z[ix][iy][ip] = res / wsum;
8936 else
8937 met->z[ix][iy][ip] = NAN;
8938 }
8939
8940 /* Free... */
8941 free(help);
8942}
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1978
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 8946 of file mptrac.c.

8951 {
8952
8953 char levname[LEN], tstr[10];
8954
8955 double rtime = 0, r, r2;
8956
8957 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
8958 year, mon, day, hour, min, sec;
8959
8960 size_t dimlen;
8961
8962 /* Set timer... */
8963 SELECT_TIMER("READ_MET_NC_GRID", "INPUT");
8964 LOG(2, "Read meteo grid information...");
8965
8966 /* MPTRAC meteo files... */
8967 if (!ctl->met_clams) {
8968
8969 /* Get time from filename... */
8970 met->time = time_from_filename(filename, 16);
8971
8972 /* Check time information from data file... */
8973 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8974 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
8975 NC(nc_get_var_double(ncid, varid, &rtime));
8976 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
8977 WARN("Time information in meteo file does not match filename!");
8978 } else
8979 WARN("Time information in meteo file is missing!");
8980 }
8981
8982 /* CLaMS meteo files... */
8983 else {
8984
8985 /* Read time from file... */
8986 NC_GET_DOUBLE("time", &rtime, 0);
8987
8988 /* Get time from filename (considering the century)... */
8989 if (rtime < 0)
8990 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
8991 else
8992 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
8993 year = atoi(tstr);
8994 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
8995 mon = atoi(tstr);
8996 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
8997 day = atoi(tstr);
8998 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
8999 hour = atoi(tstr);
9000 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
9001 }
9002
9003 /* Check time... */
9004 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
9005 || day < 1 || day > 31 || hour < 0 || hour > 23)
9006 ERRMSG("Cannot read time from filename!");
9007 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
9008 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
9009 met->time, year2, mon2, day2, hour2, min2);
9010
9011 /* Get vertical dimension... */
9012 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
9013 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
9014 ERRMSG
9015 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
9016
9017 NC(nc_inq_varndims(ncid, varid, &ndims));
9018 NC(nc_inq_vardimid(ncid, varid, dimids));
9019
9020 if (ndims == 4) {
9021 NC(nc_inq_dim
9022 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
9023 } else if (ndims == 3) {
9024 NC(nc_inq_dim
9025 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
9026 } else
9027 ERRMSG("Cannot determine vertical dimension!")
9028 met->np = (int) dimlen;
9029
9030 LOG(2, "Number of levels: %d", met->np);
9031 if (met->np < 2 || met->np > EP)
9032 ERRMSG("Number of levels out of range!");
9033
9034 if (!ctl->dd) {
9035
9036 /* Get grid dimensions... */
9037 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
9038 LOG(2, "Number of longitudes: %d", met->nx);
9039
9040 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
9041 LOG(2, "Number of latitudes: %d", met->ny);
9042
9043 /* Read longitudes and latitudes... */
9044 NC_GET_DOUBLE("lon", met->lon, 1);
9045 LOG(2, "Longitudes: %g, %g ... %g deg",
9046 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9047 NC_GET_DOUBLE("lat", met->lat, 1);
9048 LOG(2, "Latitudes: %g, %g ... %g deg",
9049 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9050
9051 } else {
9052
9053 /* Use 'naive', i.e. equidistant lat-lon domain decomposition... */
9054 read_met_nc_grid_dd_naive(dd, ctl, met, ncid);
9055
9056 }
9057
9058 /* Read pressure levels... */
9059 if (ctl->met_np <= 0) {
9060 NC_GET_DOUBLE(levname, met->p, 1);
9061 for (int ip = 0; ip < met->np; ip++)
9062 met->p[ip] /= 100.;
9063 LOG(2, "Altitude levels: %g, %g ... %g km",
9064 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
9065 LOG(2, "Pressure levels: %g, %g ... %g hPa",
9066 met->p[0], met->p[1], met->p[met->np - 1]);
9067 }
9068
9069 /* Read hybrid levels... */
9070 if (strcasecmp(levname, "hybrid") == 0)
9071 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
9072
9073 /* Read model level coefficients from file... */
9074 if (ctl->met_vert_coord == 2) {
9075 NC_GET_DOUBLE("hyam", met->hyam, 1);
9076 NC_GET_DOUBLE("hybm", met->hybm, 1);
9077 }
9078
9079 /* Copy model level coefficients from control parameters... */
9080 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
9081 if (ctl->met_nlev <= 0)
9082 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
9083 for (int ip = 0; ip < ctl->met_nlev; ip++) {
9084 met->hyam[ip] = ctl->met_lev_hyam[ip];
9085 met->hybm[ip] = ctl->met_lev_hybm[ip];
9086 }
9087 }
9088
9089 /* Calculate eta levels... */
9090 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
9091 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
9092 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
9093 ERRMSG("Eta levels must be ascending!");
9094 }
9095
9096 /* Check horizontal grid spacing... */
9097 for (int ix = 2; ix < met->nx; ix++)
9098 if (fabs
9099 (fabs(met->lon[ix] - met->lon[ix - 1]) -
9100 fabs(met->lon[1] - met->lon[0])) > 0.001)
9101 ERRMSG("No regular grid spacing in longitudes!");
9102 for (int iy = 2; iy < met->ny; iy++)
9103 if (fabs
9104 (fabs(met->lat[iy] - met->lat[iy - 1]) -
9105 fabs(met->lat[1] - met->lat[0])) > 0.001) {
9106 WARN("No regular grid spacing in latitudes!");
9107 break;
9108 }
9109}
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:11856
void read_met_nc_grid_dd_naive(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:10669
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:11955
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2548
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:2552
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3515
double eta[EP]
Model level eta values.
Definition: mptrac.h:3524
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3518
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3521
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.
  • 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 9113 of file mptrac.c.

9117 {
9118
9119 /* Set timer... */
9120 SELECT_TIMER("READ_MET_SURFACE", "INPUT");
9121 LOG(2, "Read surface data...");
9122
9123 /* Read surface pressure... */
9124 if (read_met_nc_2d
9125 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
9126 1.0f, 1)) {
9127 for (int ix = 0; ix < met->nx; ix++)
9128 for (int iy = 0; iy < met->ny; iy++)
9129 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
9130 } else
9131 if (!read_met_nc_2d
9132 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
9133 0.01f, 1)) {
9134 WARN("Cannot not read surface pressure data (use lowest level)!");
9135 for (int ix = 0; ix < met->nx; ix++)
9136 for (int iy = 0; iy < met->ny; iy++)
9137 met->ps[ix][iy]
9138 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
9139 }
9140
9141 /* MPTRAC meteo data... */
9142 if (ctl->met_clams == 0) {
9143
9144 /* Read geopotential height at the surface... */
9145 if (!read_met_nc_2d
9146 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
9147 (float) (1. / (1000. * G0)), 1))
9148 if (!read_met_nc_2d
9149 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
9150 (float) (1. / 1000.), 1))
9151 WARN("Cannot read surface geopotential height!");
9152 }
9153
9154 /* CLaMS meteo data... */
9155 else {
9156
9157 /* Read geopotential height at the surface
9158 (use lowermost level of 3-D data field)... */
9159 float *help;
9160 ALLOC(help, float,
9161 EX * EY * EP);
9162 memcpy(help, met->pl, sizeof(met->pl));
9163 if (!read_met_nc_3d
9164 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
9165 (float) (1e-3 / G0)))
9166 ERRMSG("Cannot read geopotential height!");
9167 for (int ix = 0; ix < met->nx; ix++)
9168 for (int iy = 0; iy < met->ny; iy++)
9169 met->zs[ix][iy] = met->pl[ix][iy][0];
9170 memcpy(met->pl, help, sizeof(met->pl));
9171 free(help);
9172 }
9173
9174 /* Read temperature at the surface... */
9175 if (!read_met_nc_2d
9176 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
9177 1))
9178 WARN("Cannot read surface temperature!");
9179
9180 /* Read zonal wind at the surface... */
9181 if (!read_met_nc_2d
9182 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
9183 met->us, 1.0, 1))
9184 WARN("Cannot read surface zonal wind!");
9185
9186 /* Read meridional wind at the surface... */
9187 if (!read_met_nc_2d
9188 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
9189 met->vs, 1.0, 1))
9190 WARN("Cannot read surface meridional wind!");
9191
9192 /* Read eastward turbulent surface stress... */
9193 if (!read_met_nc_2d
9194 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
9195 1.0, 1))
9196 WARN("Cannot read eastward turbulent surface stress!");
9197
9198 /* Read northward turbulent surface stress... */
9199 if (!read_met_nc_2d
9200 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
9201 1.0, 1))
9202 WARN("Cannot read nothward turbulent surface stress!");
9203
9204 /* Read surface sensible heat flux... */
9205 if (!read_met_nc_2d
9206 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
9207 1.0, 1))
9208 WARN("Cannot read surface sensible heat flux!");
9209
9210 /* Read land-sea mask... */
9211 if (!read_met_nc_2d
9212 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
9213 1.0, 1))
9214 WARN("Cannot read land-sea mask!");
9215
9216 /* Read sea surface temperature... */
9217 if (!read_met_nc_2d
9218 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
9219 1.0, 1))
9220 WARN("Cannot read sea surface temperature!");
9221
9222 /* Read PBL... */
9223 if (ctl->met_pbl == 0)
9224 if (!read_met_nc_2d
9225 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
9226 0.01f, 1))
9227 WARN("Cannot read planetary boundary layer pressure!");
9228 if (ctl->met_pbl == 1)
9229 if (!read_met_nc_2d
9230 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
9231 0.001f, 1))
9232 WARN("Cannot read planetary boundary layer height!");
9233
9234 /* Read CAPE... */
9235 if (ctl->met_cape == 0)
9236 if (!read_met_nc_2d
9237 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
9238 met->cape, 1.0, 1))
9239 WARN("Cannot read CAPE!");
9240
9241 /* Read CIN... */
9242 if (ctl->met_cape == 0)
9243 if (!read_met_nc_2d
9244 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
9245 1.0, 1))
9246 WARN("Cannot read convective inhibition!");
9247}
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:9448
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:9770
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 9251 of file mptrac.c.

9255 {
9256
9257 /* Set timer... */
9258 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT");
9259 LOG(2, "Read level data...");
9260
9261 /* Read temperature... */
9262 if (!read_met_nc_3d
9263 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
9264 ERRMSG("Cannot read temperature!");
9265
9266 /* Read horizontal wind and vertical velocity... */
9267 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
9268 ERRMSG("Cannot read zonal wind!");
9269 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
9270 ERRMSG("Cannot read meridional wind!");
9271 if (!read_met_nc_3d
9272 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
9273 WARN("Cannot read vertical velocity!");
9274
9275 /* Read water vapor... */
9276 if (!ctl->met_relhum) {
9277 if (!read_met_nc_3d
9278 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
9279 (float) (MA / MH2O)))
9280 WARN("Cannot read specific humidity!");
9281 } else {
9282 if (!read_met_nc_3d
9283 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
9284 WARN("Cannot read relative humidity!");
9285#pragma omp parallel for default(shared) collapse(2)
9286 for (int ix = 0; ix < met->nx; ix++)
9287 for (int iy = 0; iy < met->ny; iy++)
9288 for (int ip = 0; ip < met->np; ip++) {
9289 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
9290 met->h2o[ix][iy][ip] =
9291 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
9292 }
9293 }
9294
9295 /* Read ozone... */
9296 if (!read_met_nc_3d
9297 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
9298 (float) (MA / MO3)))
9299 WARN("Cannot read ozone data!");
9300
9301 /* Read cloud data... */
9302 if (!read_met_nc_3d
9303 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
9304 WARN("Cannot read cloud liquid water content!");
9305 if (!read_met_nc_3d
9306 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
9307 WARN("Cannot read cloud rain water content!");
9308 if (!read_met_nc_3d
9309 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
9310 WARN("Cannot read cloud ice water content!");
9311 if (!read_met_nc_3d
9312 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
9313 WARN("Cannot read cloud snow water content!");
9314 if (!read_met_nc_3d
9315 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
9316 WARN("Cannot read cloud cover!");
9317
9318 /* Read zeta and zeta_dot... */
9319 if (ctl->advect_vert_coord == 1) {
9320 if (!read_met_nc_3d
9321 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
9322 WARN("Cannot read ZETA!");
9323 if (!read_met_nc_3d
9324 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
9325 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
9326 WARN("Cannot read ZETA_DOT!");
9327 }
9328
9329 /* Read eta and eta_dot... */
9330 else if (ctl->advect_vert_coord == 3) {
9331#pragma omp parallel for default(shared)
9332 for (int ix = 0; ix < met->nx; ix++)
9333 for (int iy = 0; iy < met->ny; iy++)
9334 for (int ip = 0; ip < met->np; ip++)
9335 met->zetal[ix][iy][ip] =
9336 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
9337 if (!read_met_nc_3d
9338 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
9339 1.0))
9340 WARN("Cannot read eta vertical velocity!");
9341 }
9342
9343 /* Store velocities on model levels... */
9344 if (ctl->met_vert_coord != 0) {
9345#pragma omp parallel for default(shared)
9346 for (int ix = 0; ix < met->nx; ix++)
9347 for (int iy = 0; iy < met->ny; iy++)
9348 for (int ip = 0; ip < met->np; ip++) {
9349 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
9350 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
9351 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
9352 }
9353
9354 /* Save number of model levels... */
9355 met->npl = met->np;
9356 }
9357
9358 /* Get pressure on model levels... */
9359 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
9360
9361 /* Read 3-D pressure field... */
9362 if (ctl->met_vert_coord == 1) {
9363 if (!read_met_nc_3d
9364 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
9365 0.01f))
9366 if (!read_met_nc_3d
9367 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
9368 ERRMSG("Cannot read pressure on model levels!");
9369 }
9370
9371 /* Use a and b coefficients for full levels (at layer midpoints)... */
9372 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
9373
9374 /* Check number of levels... */
9375 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
9376 ERRMSG("Mismatch in number of model levels!");
9377
9378 /* Calculate pressure... */
9379 for (int ix = 0; ix < met->nx; ix++)
9380 for (int iy = 0; iy < met->ny; iy++)
9381 for (int ip = 0; ip < met->np; ip++)
9382 met->pl[ix][iy][ip] =
9383 (float) (met->hyam[ip] / 100. +
9384 met->hybm[ip] * met->ps[ix][iy]);
9385 }
9386
9387 /* Use a and b coefficients for half levels (at layer interfaces)... */
9388 else if (ctl->met_vert_coord == 4) {
9389
9390 /* Check number of levels... */
9391 if (met->np + 1 != ctl->met_nlev)
9392 ERRMSG("Mismatch in number of model levels!");
9393
9394 /* Calculate pressure... */
9395#pragma omp parallel for default(shared) collapse(2)
9396 for (int ix = 0; ix < met->nx; ix++)
9397 for (int iy = 0; iy < met->ny; iy++)
9398 for (int ip = 0; ip < met->np; ip++) {
9399 const double p0 =
9400 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
9401 const double p1 =
9402 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
9403 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
9404 }
9405 }
9406
9407 /* Check ordering of pressure levels... */
9408 for (int ix = 0; ix < met->nx; ix++)
9409 for (int iy = 0; iy < met->ny; iy++)
9410 for (int ip = 1; ip < met->np; ip++)
9411 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
9412 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
9413 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
9414 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
9415 ERRMSG("Pressure profiles are not monotonic!");
9416 }
9417
9418 /* Interpolate from model levels to pressure levels... */
9419 if (ctl->met_np > 0) {
9420
9421 /* Interpolate variables... */
9422 read_met_ml2pl(ctl, met, met->t, "T");
9423 read_met_ml2pl(ctl, met, met->u, "U");
9424 read_met_ml2pl(ctl, met, met->v, "V");
9425 read_met_ml2pl(ctl, met, met->w, "W");
9426 read_met_ml2pl(ctl, met, met->h2o, "H2O");
9427 read_met_ml2pl(ctl, met, met->o3, "O3");
9428 read_met_ml2pl(ctl, met, met->lwc, "LWC");
9429 read_met_ml2pl(ctl, met, met->rwc, "RWC");
9430 read_met_ml2pl(ctl, met, met->iwc, "IWC");
9431 read_met_ml2pl(ctl, met, met->swc, "SWC");
9432 read_met_ml2pl(ctl, met, met->cc, "CC");
9433
9434 /* Set new pressure levels... */
9435 met->np = ctl->met_np;
9436 for (int ip = 0; ip < met->np; ip++)
9437 met->p[ip] = ctl->met_p[ip];
9438 }
9439
9440 /* Check ordering of pressure levels... */
9441 for (int ip = 1; ip < met->np; ip++)
9442 if (met->p[ip - 1] < met->p[ip])
9443 ERRMSG("Pressure levels must be descending!");
9444}
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:10502
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:295
#define MO3
Molar mass of ozone [g/mol].
Definition: mptrac.h:300
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 9448 of file mptrac.c.

9461 {
9462
9463 char varsel[LEN];
9464
9465 float offset, scalfac;
9466
9467 int varid;
9468
9469 /* Check if variable exists... */
9470 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9471 sprintf(varsel, "%s", varname);
9472 else if (varname2 != NULL
9473 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9474 sprintf(varsel, "%s", varname2);
9475 else if (varname3 != NULL
9476 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9477 sprintf(varsel, "%s", varname3);
9478 else if (varname4 != NULL
9479 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9480 sprintf(varsel, "%s", varname4);
9481 else if (varname5 != NULL
9482 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
9483 sprintf(varsel, "%s", varname5);
9484 else if (varname6 != NULL
9485 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
9486 sprintf(varsel, "%s", varname6);
9487 else
9488 return 0;
9489
9490 /* Read packed data... */
9491 if (ctl->met_nc_scale && !ctl->dd
9492 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9493 && nc_get_att_float(ncid, varid, "scale_factor",
9494 &scalfac) == NC_NOERR) {
9495
9496 /* Allocate... */
9497 short *help;
9498 ALLOC(help, short,
9499 EX * EY * EP);
9500
9501 /* Read fill value and missing value... */
9502 short fillval, missval;
9503 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9504 fillval = 0;
9505 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9506 missval = 0;
9507
9508 /* Write info... */
9509 LOG(2, "Read 2-D variable: %s"
9510 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9511 varsel, fillval, missval, scalfac, offset);
9512
9513 /* Read data... */
9514 NC(nc_get_var_short(ncid, varid, help));
9515
9516 /* Check meteo data layout... */
9517 if (ctl->met_convention != 0)
9518 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9519
9520 /* Copy and check data... */
9521 omp_set_dynamic(1);
9522#pragma omp parallel for default(shared)
9523 for (int ix = 0; ix < met->nx; ix++)
9524 for (int iy = 0; iy < met->ny; iy++) {
9525 if (init)
9526 dest[ix][iy] = 0;
9527 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
9528 if ((fillval == 0 || aux != fillval)
9529 && (missval == 0 || aux != missval)
9530 && fabsf(aux * scalfac + offset) < 1e14f)
9531 dest[ix][iy] += scl * (aux * scalfac + offset);
9532 else
9533 dest[ix][iy] = NAN;
9534 }
9535 omp_set_dynamic(0);
9536
9537 /* Free... */
9538 free(help);
9539 }
9540
9541 /* Unpacked data... */
9542 else if (!ctl->dd) {
9543
9544 /* Allocate... */
9545 float *help;
9546 ALLOC(help, float,
9547 EX * EY);
9548
9549 /* Read fill value and missing value... */
9550 float fillval, missval;
9551 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9552 fillval = 0;
9553 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9554 missval = 0;
9555
9556 /* Write info... */
9557 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
9558 varsel, fillval, missval);
9559
9560 /* Read data... */
9561 NC(nc_get_var_float(ncid, varid, help));
9562
9563 /* Check meteo data layout... */
9564 if (ctl->met_convention == 0) {
9565
9566 /* Copy and check data (ordering: lat, lon)... */
9567 omp_set_dynamic(1);
9568#pragma omp parallel for default(shared)
9569 for (int ix = 0; ix < met->nx; ix++)
9570 for (int iy = 0; iy < met->ny; iy++) {
9571 if (init)
9572 dest[ix][iy] = 0;
9573 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
9574 if ((fillval == 0 || aux != fillval)
9575 && (missval == 0 || aux != missval)
9576 && fabsf(aux) < 1e14f)
9577 dest[ix][iy] += scl * aux;
9578 else
9579 dest[ix][iy] = NAN;
9580 }
9581 omp_set_dynamic(0);
9582
9583 } else {
9584
9585 /* Copy and check data (ordering: lon, lat)... */
9586 omp_set_dynamic(1);
9587#pragma omp parallel for default(shared)
9588 for (int iy = 0; iy < met->ny; iy++)
9589 for (int ix = 0; ix < met->nx; ix++) {
9590 if (init)
9591 dest[ix][iy] = 0;
9592 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
9593 if ((fillval == 0 || aux != fillval)
9594 && (missval == 0 || aux != missval)
9595 && fabsf(aux) < 1e14f)
9596 dest[ix][iy] += scl * aux;
9597 else
9598 dest[ix][iy] = NAN;
9599 }
9600 omp_set_dynamic(0);
9601 }
9602
9603 /* Free... */
9604 free(help);
9605 }
9606
9607 /* Domain decomposed data... */
9608 else {
9609
9610 /* Read fill value and missing value... */
9611 float fillval, missval;
9612 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9613 fillval = 0;
9614 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9615 missval = 0;
9616
9617 /* Write info... */
9618 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
9619 varsel, fillval, missval);
9620
9621 /* Define hyperslab... */
9622 float *help;
9623 size_t help_subdomain_start[3];
9624 size_t help_subdomain_count[3];
9625
9626 help_subdomain_start[0] = 0;
9627 if (ctl->met_convention == 0) {
9628 help_subdomain_start[1] = dd->subdomain_start[2];
9629 help_subdomain_start[2] = dd->subdomain_start[3];
9630 } else {
9631 help_subdomain_start[1] = dd->subdomain_start[3];
9632 help_subdomain_start[2] = dd->subdomain_start[2];
9633 }
9634
9635 help_subdomain_count[0] = 1;
9636 if (ctl->met_convention == 0) {
9637 help_subdomain_count[1] = dd->subdomain_count[2]; //y
9638 help_subdomain_count[2] = dd->subdomain_count[3]; //x
9639 } else {
9640 help_subdomain_count[1] = dd->subdomain_count[3]; //x
9641 help_subdomain_count[2] = dd->subdomain_count[2]; //y
9642 }
9643
9644 ALLOC(help, float,
9645 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
9646
9647 /* Read data... */
9648#ifdef DD
9649 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
9650#endif
9651 NC(nc_get_vara_float
9652 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
9653
9654 /* Read halos at boundaries... */
9655 size_t help_halo_bnd_start[3];
9656 size_t help_halo_bnd_count[3];
9657
9658 help_halo_bnd_start[0] = 0;
9659 if (ctl->met_convention == 0) {
9660 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
9661 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
9662 } else {
9663 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
9664 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
9665 }
9666
9667 help_halo_bnd_count[0] = 1;
9668 if (ctl->met_convention == 0) {
9669 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
9670 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
9671 } else {
9672 help_halo_bnd_count[1] = dd->halo_bnd_count[3]; //x
9673 help_halo_bnd_count[2] = dd->halo_bnd_count[2]; //y
9674 }
9675
9676 float *help_halo;
9677 ALLOC(help_halo, float,
9678 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
9679
9680#ifdef DD
9681 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
9682#endif
9683 NC(nc_get_vara_float
9684 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
9685
9686 /* Check meteo data layout... */
9687 if (ctl->met_convention == 0) {
9688
9689 /* Copy and check data (ordering: lat, lon)... */
9690 omp_set_dynamic(1);
9691#pragma omp parallel for default(shared)
9692 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
9693 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
9694 if (init == 1)
9695 dest[ix + dd->halo_offset_start][iy] = 0;
9696 const float aux =
9697 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
9698 if ((fillval == 0 || aux != fillval)
9699 && (missval == 0 || aux != missval)
9700 && fabsf(aux) < 1e14f) {
9701 dest[ix + dd->halo_offset_start][iy] += scl * aux;
9702 } else
9703 dest[ix + dd->halo_offset_start][iy] = NAN;
9704 }
9705
9706#pragma omp parallel for default(shared)
9707 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
9708 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
9709 if (init == 1)
9710 dest[ix + dd->halo_offset_end][iy] = 0;
9711 const float aux =
9712 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
9713 if ((fillval == 0 || aux != fillval)
9714 && (missval == 0 || aux != missval)
9715 && fabsf(aux) < 1e14f)
9716 dest[ix + dd->halo_offset_end][iy] += scl * aux;
9717 else {
9718 dest[ix + dd->halo_offset_end][iy] = NAN;
9719 }
9720 }
9721 omp_set_dynamic(0);
9722
9723 } else {
9724
9725 /* Copy and check data (ordering: lon, lat)... */
9726 omp_set_dynamic(1);
9727#pragma omp parallel for default(shared)
9728 for (int ix = 0; ix < (int) help_subdomain_count[1]; ix++)
9729 for (int iy = 0; iy < (int) help_subdomain_count[2]; iy++) {
9730 if (init == 1)
9731 dest[ix + dd->halo_offset_start][iy] = 0;
9732 const float aux =
9733 help[ARRAY_2D(ix, iy, (int) help_subdomain_count[1])];
9734 if ((fillval == 0 || aux != fillval)
9735 && (missval == 0 || aux != missval)
9736 && fabsf(aux) < 1e14f)
9737 dest[ix + dd->halo_offset_start][iy] += scl * aux;
9738 else
9739 dest[ix + dd->halo_offset_start][iy] = NAN;
9740 }
9741
9742#pragma omp parallel for default(shared)
9743 for (int ix = 0; ix < (int) help_halo_bnd_count[1]; ix++)
9744 for (int iy = 0; iy < (int) help_halo_bnd_count[2]; iy++) {
9745 if (init == 1)
9746 dest[ix + dd->halo_offset_end][iy] = 0;
9747 const float aux =
9748 help_halo[ARRAY_2D(ix, iy, (int) help_halo_bnd_count[1])];
9749 if ((fillval == 0 || aux != fillval)
9750 && (missval == 0 || aux != missval)
9751 && fabsf(aux) < 1e14f)
9752 dest[ix + dd->halo_offset_end][iy] += scl * aux;
9753 else
9754 dest[ix + dd->halo_offset_end][iy] = NAN;
9755 }
9756 omp_set_dynamic(0);
9757 }
9758
9759 /* Free... */
9760 free(help);
9761 free(help_halo);
9762 }
9763
9764 /* Return... */
9765 return 1;
9766}
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2562
size_t halo_bnd_count[4]
Extent of the periodic boundary halo hyperslab.
Definition: mptrac.h:3694
int halo_offset_end
Offset of the periodic halo block at the end of the local x-array.
Definition: mptrac.h:3700
size_t halo_bnd_start[4]
Start indices of the periodic boundary halo hyperslab.
Definition: mptrac.h:3691
int halo_offset_start
Offset of the periodic halo block at the beginning of the local x-array.
Definition: mptrac.h:3697
size_t subdomain_count[4]
Extent of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:3688
size_t subdomain_start[4]
Start indices of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:3685

◆ 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 9770 of file mptrac.c.

9780 {
9781
9782 char varsel[LEN];
9783
9784 float offset, scalfac;
9785
9786 int varid;
9787
9788 /* Check if variable exists... */
9789 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9790 sprintf(varsel, "%s", varname);
9791 else if (varname2 != NULL
9792 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9793 sprintf(varsel, "%s", varname2);
9794 else if (varname3 != NULL
9795 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9796 sprintf(varsel, "%s", varname3);
9797 else if (varname4 != NULL
9798 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9799 sprintf(varsel, "%s", varname4);
9800 else
9801 return 0;
9802
9803 /* Read packed data... */
9804 if (ctl->met_nc_scale && !ctl->dd
9805 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9806 && nc_get_att_float(ncid, varid, "scale_factor",
9807 &scalfac) == NC_NOERR) {
9808
9809 /* Allocate... */
9810 short *help;
9811 ALLOC(help, short,
9812 EX * EY * EP);
9813
9814 /* Read fill value and missing value... */
9815 short fillval, missval;
9816 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9817 fillval = 0;
9818 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9819 missval = 0;
9820
9821 /* Write info... */
9822 LOG(2, "Read 3-D variable: %s "
9823 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9824 varsel, fillval, missval, scalfac, offset);
9825
9826 /* Read data... */
9827 NC(nc_get_var_short(ncid, varid, help));
9828
9829 /* Check meteo data layout... */
9830 if (ctl->met_convention != 0)
9831 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9832
9833 /* Copy and check data... */
9834 omp_set_dynamic(1);
9835#pragma omp parallel for default(shared)
9836 for (int ix = 0; ix < met->nx; ix++)
9837 for (int iy = 0; iy < met->ny; iy++)
9838 for (int ip = 0; ip < met->np; ip++) {
9839 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9840 if ((fillval == 0 || aux != fillval)
9841 && (missval == 0 || aux != missval)
9842 && fabsf(aux * scalfac + offset) < 1e14f)
9843 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
9844 else
9845 dest[ix][iy][ip] = NAN;
9846 }
9847 omp_set_dynamic(0);
9848
9849 /* Free... */
9850 free(help);
9851 }
9852
9853 /* Unpacked data... */
9854 else if (!ctl->dd) {
9855
9856 /* Allocate... */
9857 float *help;
9858 ALLOC(help, float,
9859 EX * EY * EP);
9860
9861 /* Read fill value and missing value... */
9862 float fillval, missval;
9863 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9864 fillval = 0;
9865 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9866 missval = 0;
9867
9868 /* Write info... */
9869 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9870 varsel, fillval, missval);
9871
9872 /* Read data... */
9873 NC(nc_get_var_float(ncid, varid, help));
9874
9875 /* Check meteo data layout... */
9876 if (ctl->met_convention == 0) {
9877
9878 /* Copy and check data (ordering: lev, lat, lon)... */
9879 omp_set_dynamic(1);
9880#pragma omp parallel for default(shared)
9881 for (int ix = 0; ix < met->nx; ix++)
9882 for (int iy = 0; iy < met->ny; iy++)
9883 for (int ip = 0; ip < met->np; ip++) {
9884 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9885 if ((fillval == 0 || aux != fillval)
9886 && (missval == 0 || aux != missval)
9887 && fabsf(aux) < 1e14f)
9888 dest[ix][iy][ip] = scl * aux;
9889 else
9890 dest[ix][iy][ip] = NAN;
9891 }
9892 omp_set_dynamic(0);
9893
9894 } else {
9895
9896 /* Copy and check data (ordering: lon, lat, lev)... */
9897 omp_set_dynamic(1);
9898#pragma omp parallel for default(shared)
9899 for (int ip = 0; ip < met->np; ip++)
9900 for (int iy = 0; iy < met->ny; iy++)
9901 for (int ix = 0; ix < met->nx; ix++) {
9902 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9903 if ((fillval == 0 || aux != fillval)
9904 && (missval == 0 || aux != missval)
9905 && fabsf(aux) < 1e14f)
9906 dest[ix][iy][ip] = scl * aux;
9907 else
9908 dest[ix][iy][ip] = NAN;
9909 }
9910 omp_set_dynamic(0);
9911 }
9912
9913 /* Free... */
9914 free(help);
9915 }
9916
9917 /* Domain decomposed data... */
9918 else {
9919
9920 /* Read fill value and missing value... */
9921 float fillval, missval;
9922 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9923 fillval = 0;
9924 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9925 missval = 0;
9926
9927 /* Write info... */
9928 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9929 varsel, fillval, missval);
9930
9931 /* Define hyperslab... */
9932 size_t help_subdomain_start[4];
9933 size_t help_subdomain_count[4];
9934 size_t help_halo_bnd_start[4];
9935 size_t help_halo_bnd_count[4];
9936
9937 if (ctl->met_convention == 0) {
9938 for (int i = 0; i < 4; i++) {
9939 help_subdomain_start[i] = dd->subdomain_start[i];
9940 help_subdomain_count[i] = dd->subdomain_count[i];
9941 help_halo_bnd_start[i] = dd->halo_bnd_start[i];
9942 help_halo_bnd_count[i] = dd->halo_bnd_count[i];
9943 }
9944 } else {
9945 help_subdomain_start[0] = dd->subdomain_start[0];
9946 help_subdomain_start[1] = dd->subdomain_start[3];
9947 help_subdomain_start[2] = dd->subdomain_start[2];
9948 help_subdomain_start[3] = dd->subdomain_start[1];
9949
9950 help_subdomain_count[0] = dd->subdomain_count[0];
9951 help_subdomain_count[1] = dd->subdomain_count[3];
9952 help_subdomain_count[2] = dd->subdomain_count[2];
9953 help_subdomain_count[3] = dd->subdomain_count[1];
9954
9955 help_halo_bnd_start[0] = dd->halo_bnd_start[0];
9956 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
9957 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
9958 help_halo_bnd_start[3] = dd->halo_bnd_start[1];
9959
9960 help_halo_bnd_count[0] = dd->halo_bnd_count[0];
9961 help_halo_bnd_count[1] = dd->halo_bnd_count[3];
9962 help_halo_bnd_count[2] = dd->halo_bnd_count[2];
9963 help_halo_bnd_count[3] = dd->halo_bnd_count[1];
9964 }
9965
9966 /* Allocate... */
9967 float *help;
9968 ALLOC(help, float,
9969 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
9970 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
9971
9972 /* Use default NetCDF parallel I/O behavior */
9973#ifdef DD
9974 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
9975#endif
9976 NC(nc_get_vara_float
9977 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
9978
9979 /* Read halos separately at boundaries... */
9980 float *help_halo;
9981 ALLOC(help_halo, float,
9982 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
9983 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
9984
9985 /* Halo read also uses independent access */
9986#ifdef DD
9987 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
9988#endif
9989 NC(nc_get_vara_float(ncid,
9990 varid,
9991 help_halo_bnd_start, help_halo_bnd_count,
9992 help_halo));
9993
9994 /* Check meteo data layout... */
9995 if (ctl->met_convention == 0) {
9996
9997 /* Copy and check data (ordering: lev, lat, lon)... */
9998 omp_set_dynamic(1);
9999#pragma omp parallel for default(shared)
10000 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10001 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10002 for (int ip = 0; ip < met->np; ip++) {
10003 const float aux =
10004 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
10005 (int) dd->subdomain_count[3])];
10006 if ((fillval == 0 || aux != fillval)
10007 && (missval == 0 || aux != missval)
10008 && fabsf(aux) < 1e14f)
10009 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10010 else
10011 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10012 }
10013
10014#pragma omp parallel for default(shared)
10015 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10016 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10017 for (int ip = 0; ip < met->np; ip++) {
10018 const float aux =
10019 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
10020 (int) dd->halo_bnd_count[3])];
10021 if ((fillval == 0 || aux != fillval)
10022 && (missval == 0 || aux != missval)
10023 && fabsf(aux) < 1e14f)
10024 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10025 else
10026 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10027 }
10028 omp_set_dynamic(0);
10029
10030 } else {
10031
10032 /* Copy and check data (ordering: lon, lat, lev)... */
10033 omp_set_dynamic(1);
10034#pragma omp parallel for default(shared)
10035 for (int ip = 0; ip < met->np; ip++)
10036 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10037 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
10038 const float aux =
10039 help[ARRAY_3D
10040 (ix, iy, (int) dd->subdomain_count[2], ip, met->np)];
10041 if ((fillval == 0 || aux != fillval)
10042 && (missval == 0 || aux != missval)
10043 && fabsf(aux) < 1e14f)
10044 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10045 else
10046 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10047 }
10048
10049#pragma omp parallel for default(shared)
10050 for (int ip = 0; ip < met->np; ip++)
10051 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10052 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
10053 const float aux =
10054 help_halo[ARRAY_3D(ix, iy, (int) dd->halo_bnd_count[2], ip,
10055 met->np)];
10056 if ((fillval == 0 || aux != fillval)
10057 && (missval == 0 || aux != missval)
10058 && fabsf(aux) < 1e14f)
10059 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10060 else
10061 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10062 }
10063 omp_set_dynamic(0);
10064 }
10065
10066 /* Free... */
10067 free(help);
10068 free(help_halo);
10069 }
10070
10071 /* Return... */
10072 return 1;
10073}

◆ 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 10502 of file mptrac.c.

10506 {
10507
10508 double aux[EP], p[EP];
10509
10510 /* Set timer... */
10511 SELECT_TIMER("READ_MET_ML2PL", "METPROC");
10512 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
10513
10514 /* Loop over columns... */
10515#pragma omp parallel for default(shared) private(aux,p) collapse(2)
10516 for (int ix = 0; ix < met->nx; ix++)
10517 for (int iy = 0; iy < met->ny; iy++) {
10518
10519 /* Copy pressure profile... */
10520 for (int ip = 0; ip < met->np; ip++)
10521 p[ip] = met->pl[ix][iy][ip];
10522
10523 /* Interpolate... */
10524 for (int ip = 0; ip < ctl->met_np; ip++) {
10525 double pt = ctl->met_p[ip];
10526 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
10527 pt = p[0];
10528 else if ((pt > p[met->np - 1] && p[1] > p[0])
10529 || (pt < p[met->np - 1] && p[1] < p[0]))
10530 pt = p[met->np - 1];
10531 const int ip2 = locate_irr(p, met->np, pt);
10532 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
10533 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
10534 }
10535
10536 /* Copy data... */
10537 for (int ip = 0; ip < ctl->met_np; ip++)
10538 var[ix][iy][ip] = (float) aux[ip];
10539 }
10540}
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 10544 of file mptrac.c.

10546 {
10547
10548 /* Check parameters... */
10549 if (ctl->advect_vert_coord != 1)
10550 return;
10551
10552 /* Set timer... */
10553 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC");
10554 LOG(2, "Make zeta profiles monotone...");
10555
10556 /* Create monotone zeta profiles... */
10557#pragma omp parallel for default(shared) collapse(2)
10558 for (int i = 0; i < met->nx; i++)
10559 for (int j = 0; j < met->ny; j++) {
10560 int k = 1;
10561
10562 while (k < met->npl) { /* Check if there is an inversion at level k... */
10563 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
10564 /* Find the upper level k+l over the inversion... */
10565 int l = 0;
10566 do {
10567 l++;
10568 }
10569 while ((met->zetal[i][j][k - 1] >=
10570 met->zetal[i][j][k + l]) & (k + l < met->npl));
10571
10572 /* Interpolate linear between the top and bottom
10573 of the inversion... */
10574 float s =
10575 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
10576 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
10577
10578 for (int m = k; m < k + l; m++) {
10579 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
10580 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
10581 }
10582
10583 /* Search for more inversions above the last inversion ... */
10584 k = k + l;
10585 } else {
10586 k++;
10587 }
10588 }
10589 }
10590
10591 /* Create monotone pressure profiles... */
10592#pragma omp parallel for default(shared) collapse(2)
10593 for (int i = 0; i < met->nx; i++)
10594 for (int j = 0; j < met->ny; j++) {
10595 int k = 1;
10596
10597 while (k < met->npl) { /* Check if there is an inversion at level k... */
10598 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
10599
10600 /* Find the upper level k+l over the inversion... */
10601 int l = 0;
10602 do {
10603 l++;
10604 }
10605 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
10606 met->npl));
10607
10608 /* Interpolate linear between the top and bottom
10609 of the inversion... */
10610 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
10611 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
10612
10613 for (int m = k; m < k + l; m++) {
10614 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
10615 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
10616 }
10617
10618 /* Search for more inversions above the last inversion ... */
10619 k += l;
10620 } else {
10621 k++;
10622 }
10623 }
10624 }
10625}

◆ 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 10629 of file mptrac.c.

10633 {
10634
10635 int ncid;
10636
10637 /* Open file... */
10638#ifdef DD
10639 if (ctl->dd) {
10640 NC(nc_open_par
10641 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
10642 &ncid))
10643 }
10644#else
10645 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
10646 WARN("Cannot open file!");
10647 return 0;
10648 }
10649#endif
10650
10651 /* Read coordinates of meteo data... */
10652 read_met_nc_grid(filename, ncid, ctl, met, dd);
10653
10654 /* Read surface data... */
10655 read_met_nc_surface(ncid, ctl, met, dd);
10656
10657 /* Read meteo data on vertical levels... */
10658 read_met_nc_levels(ncid, ctl, met, dd);
10659
10660 /* Close file... */
10661 NC(nc_close(ncid));
10662
10663 /* Return success... */
10664 return 1;
10665}
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:9251
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:9113
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:8946
Here is the call graph for this function:

◆ read_met_nc_grid_dd_naive()

void read_met_nc_grid_dd_naive ( 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 10669 of file mptrac.c.

10673 {
10674
10675 int varid;
10676
10677 /* Get the MPI information... */
10678 int rank = 0, size = 1;
10679#ifdef MPI
10680 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
10681 MPI_Comm_size(MPI_COMM_WORLD, &size);
10682#endif
10683
10684 /* Get grid dimensions... */
10685 NC_INQ_DIM("lon", &dd->nx_glob, 0, 0, 0);
10686 NC_INQ_DIM("lat", &dd->ny_glob, 0, 0, 0);
10687
10688 LOG(2, "Number of longitudes: %d", dd->nx_glob);
10689 LOG(2, "Number of latitudes: %d", dd->ny_glob);
10690
10691 /* Check grid... */
10692 if (dd->nx_glob > DD_EX_GLOB || dd->ny_glob > DD_EY_GLOB)
10693 ERRMSG("Global grid is too large!");
10694
10695 if (ctl->dd_subdomains_zonal > dd->nx_glob)
10696 ERRMSG("Too many zonal subdomains for global x grid!");
10697
10698 if (ctl->dd_subdomains_meridional > dd->ny_glob)
10699 ERRMSG("Too many meridional subdomains for global y grid!");
10700
10701 /* Read global longitudes and latitudes... */
10702 NC_GET_DOUBLE("lon", dd->lon_glob, 1);
10703 NC_GET_DOUBLE("lat", dd->lat_glob, 1);
10704
10705 LOG(2, "Longitudes: %g, %g ... %g deg",
10706 dd->lon_glob[0], dd->lon_glob[1], dd->lon_glob[dd->nx_glob - 1]);
10707 LOG(2, "Latitudes: %g, %g ... %g deg",
10708 dd->lat_glob[0], dd->lat_glob[1], dd->lat_glob[dd->ny_glob - 1]);
10709
10710 /* Rank coordinates in DD layout... */
10711 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
10712 const int merid_rank = rank % ctl->dd_subdomains_meridional;
10713
10714 /* Check for edge cases... */
10715 const int left = (zonal_rank == 0);
10716 const int right = (zonal_rank == ctl->dd_subdomains_zonal - 1);
10717 const int top = (merid_rank == 0);
10718 const int bottom = (merid_rank == ctl->dd_subdomains_meridional - 1);
10719
10720 /* Core owned block (without halos)... */
10721 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
10722 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
10723
10724 const int ix0 = zonal_rank * nx_block;
10725 const int iy0 = merid_rank * ny_block;
10726
10727 int nx_core = nx_block;
10728 int ny_core = ny_block;
10729
10730 if (right)
10731 nx_core += dd->nx_glob - ctl->dd_subdomains_zonal * nx_block;
10732 if (bottom)
10733 ny_core += dd->ny_glob - ctl->dd_subdomains_meridional * ny_block;
10734
10735 /* Store core met size first... */
10736 met->nx = nx_core;
10737 met->ny = ny_core;
10738
10739 /* Set hyperslab for core subdomain... */
10740 dd->subdomain_start[0] = 0;
10741 dd->subdomain_start[1] = 0;
10742 dd->subdomain_start[2] = (size_t) iy0;
10743 dd->subdomain_start[3] = (size_t) ix0;
10744
10745 dd->subdomain_count[0] = 1;
10746 dd->subdomain_count[1] = (size_t) met->np;
10747 dd->subdomain_count[2] = (size_t) ny_core;
10748 dd->subdomain_count[3] = (size_t) nx_core;
10749
10750 /* Add inner halos to read window... */
10751 if (!left && !right) {
10752 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
10753 dd->subdomain_count[3] += (size_t) (2 * ctl->dd_halos_size);
10754 } else if (left ^ right) {
10755 dd->subdomain_count[3] += (size_t) ctl->dd_halos_size;
10756 if (!left)
10757 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
10758 }
10759
10760 if (!top && !bottom) {
10761 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
10762 dd->subdomain_count[2] += (size_t) (2 * ctl->dd_halos_size);
10763 } else if (top ^ bottom) {
10764 dd->subdomain_count[2] += (size_t) ctl->dd_halos_size;
10765 if (!top)
10766 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
10767 }
10768
10769 /* Set boundary halo hyperslabs... */
10770 double lon_shift = 0.0;
10771
10772 if (left ^ right) {
10773 dd->halo_bnd_start[0] = 0;
10774 dd->halo_bnd_start[1] = 0;
10775 dd->halo_bnd_start[2] = dd->subdomain_start[2];
10776 dd->halo_bnd_start[3] =
10777 (size_t) (left ? (dd->nx_glob - ctl->dd_halos_size) : 0);
10778
10779 dd->halo_bnd_count[0] = 1;
10780 dd->halo_bnd_count[1] = (size_t) met->np;
10781 dd->halo_bnd_count[2] =
10782 (size_t) met->ny +
10783 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
10784 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
10785
10786 dd->halo_offset_start = left ? (int) dd->halo_bnd_count[3] : 0;
10787 dd->halo_offset_end = left ? 0 : (int) dd->subdomain_count[3];
10788 lon_shift = left ? -360.0 : 360.0;
10789 } else {
10790 dd->halo_bnd_start[0] = 0;
10791 dd->halo_bnd_start[1] = 0;
10792 dd->halo_bnd_start[2] = 0;
10793 dd->halo_bnd_start[3] = 0;
10794
10795 dd->halo_bnd_count[0] = 0;
10796 dd->halo_bnd_count[1] = 0;
10797 dd->halo_bnd_count[2] = 0;
10798 dd->halo_bnd_count[3] = 0;
10799
10800 dd->halo_offset_start = 0;
10801 dd->halo_offset_end = 0;
10802 }
10803
10804 /* Focus on subdomain latitudes... */
10805 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10806 met->lat[iy] = dd->lat_glob[(int) dd->subdomain_start[2] + iy];
10807
10808 /* Focus on subdomain longitudes... */
10809 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10810 met->lon[ix + dd->halo_offset_start] =
10811 dd->lon_glob[(int) dd->subdomain_start[3] + ix];
10812
10813 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10814 met->lon[ix + dd->halo_offset_end] =
10815 dd->lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
10816
10817 /* Reset halo-extended grid dimensions... */
10818 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
10819 met->ny = (int) dd->subdomain_count[2];
10820
10821 LOG(2, "Define subdomain properties.");
10822 LOG(2, "MPI information: Rank %d, Size %d", rank, size);
10823 LOG(2, "Edge position: l=%d,r=%d,t=%d,b=%d", left, right, top, bottom);
10824 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d",
10825 met->nx, met->ny, met->np);
10826 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
10827 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
10828 (int) dd->halo_bnd_count[1]);
10829 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
10830 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
10831 (int) dd->subdomain_count[1]);
10832 LOG(2, "Subdomain start: nx %ld ny %ld np %ld",
10833 dd->subdomain_start[3], dd->subdomain_start[2], dd->subdomain_start[1]);
10834 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld",
10835 dd->halo_bnd_start[3], dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
10836 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
10837 LOG(2, "%d Subdomain longitudes: %g, %g ... %g deg",
10838 rank, met->lon[0], met->lon[1], met->lon[met->nx - 1]);
10839 LOG(2, "%d Subdomain latitudes: %g, %g ... %g deg",
10840 rank, met->lat[0], met->lat[1], met->lat[met->ny - 1]);
10841}
#define DD_EY_GLOB
Maximum number of latitudes of global meteo data.
Definition: mptrac.h:424
#define DD_EX_GLOB
Maximum number of longitudes of global meteo data.
Definition: mptrac.h:419
double lon_glob[DD_EX_GLOB]
Longitudes of the global grid [deg].
Definition: mptrac.h:3675
double lat_glob[DD_EY_GLOB]
Latitudes of the global grid [deg].
Definition: mptrac.h:3678
int ny_glob
Number of global latitudes.
Definition: mptrac.h:3672

◆ 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 10845 of file mptrac.c.

10847 {
10848
10849 /* Set timer... */
10850 SELECT_TIMER("READ_MET_PBL", "METPROC");
10851 LOG(2, "Calculate planetary boundary layer...");
10852
10853 /* Convert PBL height from meteo file to pressure... */
10854 if (ctl->met_pbl == 1) {
10855
10856 /* Loop over grid points... */
10857#pragma omp parallel for default(shared) collapse(2)
10858 for (int ix = 0; ix < met->nx; ix++)
10859 for (int iy = 0; iy < met->ny; iy++) {
10860
10861 /* Get pressure at top of PBL... */
10862 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
10863 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
10864 met->pbl[ix][iy] =
10865 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
10866 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
10867 }
10868 }
10869
10870 /* Determine PBL based on Richardson number... */
10871 else if (ctl->met_pbl == 2) {
10872
10873 /* Parameters used to estimate the height of the PBL
10874 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
10875 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
10876
10877 /* Loop over grid points... */
10878#pragma omp parallel for default(shared) collapse(2)
10879 for (int ix = 0; ix < met->nx; ix++)
10880 for (int iy = 0; iy < met->ny; iy++) {
10881
10882 /* Set bottom level of PBL... */
10883 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
10884
10885 /* Find lowest level near the bottom... */
10886 int ip;
10887 for (ip = 1; ip < met->np; ip++)
10888 if (met->p[ip] < pbl_bot)
10889 break;
10890
10891 /* Get near surface data... */
10892 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
10893 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
10894 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
10895
10896 /* Init... */
10897 double rib_old = 0;
10898
10899 /* Loop over levels... */
10900 for (; ip < met->np; ip++) {
10901
10902 /* Get squared horizontal wind speed... */
10903 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
10904 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
10905 vh2 = MAX(vh2, SQR(umin));
10906
10907 /* Calculate bulk Richardson number... */
10908 const double rib =
10909 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
10910 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
10911 met->h2o[ix][iy][ip]) - tvs) / vh2;
10912
10913 /* Check for critical value... */
10914 if (rib >= rib_crit) {
10915 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
10916 rib, met->p[ip], rib_crit));
10917 if (met->pbl[ix][iy] > pbl_bot)
10918 met->pbl[ix][iy] = (float) pbl_bot;
10919 break;
10920 }
10921
10922 /* Save Richardson number... */
10923 rib_old = rib;
10924 }
10925 }
10926 }
10927
10928 /* Determine PBL based on potential temperature... */
10929 if (ctl->met_pbl == 3) {
10930
10931 /* Parameters used to estimate the height of the PBL
10932 (following HYSPLIT model)... */
10933 const double dtheta = 2.0, zmin = 0.1;
10934
10935 /* Loop over grid points... */
10936#pragma omp parallel for default(shared) collapse(2)
10937 for (int ix = 0; ix < met->nx; ix++)
10938 for (int iy = 0; iy < met->ny; iy++) {
10939
10940 /* Potential temperature at the surface... */
10941 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
10942
10943 /* Find topmost level where theta exceeds surface value by 2 K... */
10944 int ip;
10945 for (ip = met->np - 2; ip > 0; ip--)
10946 if (met->p[ip] >= 300.)
10947 if (met->p[ip] > met->ps[ix][iy]
10948 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
10949 break;
10950
10951 /* Interpolate... */
10952 met->pbl[ix][iy]
10953 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
10954 met->p[ip + 1],
10955 THETA(met->p[ip], met->t[ix][iy][ip]),
10956 met->p[ip], theta0 + dtheta));
10957
10958 /* Check minimum value... */
10959 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
10960 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
10961 met->pbl[ix][iy] = (float) pbl_min;
10962 }
10963 }
10964
10965 /* Loop over grid points... */
10966#pragma omp parallel for default(shared) collapse(2)
10967 for (int ix = 0; ix < met->nx; ix++)
10968 for (int iy = 0; iy < met->ny; iy++) {
10969
10970 /* Check minimum value... */
10971 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
10972 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
10973
10974 /* Check maximum value... */
10975 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
10976 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
10977 }
10978}
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 10982 of file mptrac.c.

10983 {
10984
10985 /* Set timer... */
10986 SELECT_TIMER("READ_MET_PERIODIC", "METPROC");
10987 LOG(2, "Apply periodic boundary conditions...");
10988
10989 /* Check longitudes... */
10990 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
10991 + met->lon[1] - met->lon[0] - 360) < 0.01))
10992 return;
10993
10994 /* Increase longitude counter... */
10995 if ((++met->nx) >= EX)
10996 ERRMSG("Cannot create periodic boundary conditions!");
10997
10998 /* Set longitude... */
10999 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
11000
11001 /* Loop over latitudes and pressure levels... */
11002#pragma omp parallel for default(shared)
11003 for (int iy = 0; iy < met->ny; iy++) {
11004 met->ps[met->nx - 1][iy] = met->ps[0][iy];
11005 met->zs[met->nx - 1][iy] = met->zs[0][iy];
11006 met->ts[met->nx - 1][iy] = met->ts[0][iy];
11007 met->us[met->nx - 1][iy] = met->us[0][iy];
11008 met->vs[met->nx - 1][iy] = met->vs[0][iy];
11009 met->ess[met->nx - 1][iy] = met->ess[0][iy];
11010 met->nss[met->nx - 1][iy] = met->nss[0][iy];
11011 met->shf[met->nx - 1][iy] = met->shf[0][iy];
11012 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
11013 met->sst[met->nx - 1][iy] = met->sst[0][iy];
11014 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
11015 met->cape[met->nx - 1][iy] = met->cape[0][iy];
11016 met->cin[met->nx - 1][iy] = met->cin[0][iy];
11017 for (int ip = 0; ip < met->np; ip++) {
11018 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
11019 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
11020 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
11021 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
11022 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
11023 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
11024 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
11025 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
11026 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
11027 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
11028 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
11029 }
11030 for (int ip = 0; ip < met->npl; ip++) {
11031 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
11032 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
11033 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
11034 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
11035 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
11036 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
11037 }
11038 }
11039}

◆ 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 11043 of file mptrac.c.

11044 {
11045
11046 /* Set timer... */
11047 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC");
11048 LOG(2, "Apply fix for polar winds...");
11049
11050 /* Check latitudes... */
11051 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
11052 return;
11053
11054 /* Loop over hemispheres... */
11055 for (int ihem = 0; ihem < 2; ihem++) {
11056
11057 /* Set latitude indices... */
11058 int i89 = 1, i90 = 0, sign = 1;
11059 if (ihem == 1) {
11060 i89 = met->ny - 2;
11061 i90 = met->ny - 1;
11062 }
11063 if (met->lat[i90] < 0)
11064 sign = -1;
11065
11066 /* Look-up table of cosinus and sinus... */
11067 double clon[EX], slon[EX];
11068#pragma omp parallel for default(shared)
11069 for (int ix = 0; ix < met->nx; ix++) {
11070 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
11071 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
11072 }
11073
11074 /* Loop over levels... */
11075#pragma omp parallel for default(shared)
11076 for (int ip = 0; ip < met->np; ip++) {
11077
11078 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
11079 double vel89x = 0, vel89y = 0;
11080 for (int ix = 0; ix < met->nx; ix++) {
11081 vel89x +=
11082 (met->u[ix][i89][ip] * clon[ix] -
11083 met->v[ix][i89][ip] * slon[ix]) / met->nx;
11084 vel89y +=
11085 (met->u[ix][i89][ip] * slon[ix] +
11086 met->v[ix][i89][ip] * clon[ix]) / met->nx;
11087 }
11088
11089 /* Replace 90 degree winds by 89 degree mean... */
11090 for (int ix = 0; ix < met->nx; ix++) {
11091 met->u[ix][i90][ip]
11092 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
11093 met->v[ix][i90][ip]
11094 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
11095 }
11096 }
11097 }
11098}

◆ 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 11102 of file mptrac.c.

11103 {
11104
11105 double pows[EP];
11106
11107 /* Set timer... */
11108 SELECT_TIMER("READ_MET_PV", "METPROC");
11109 LOG(2, "Calculate potential vorticity...");
11110
11111 /* Set powers... */
11112#pragma omp parallel for default(shared)
11113 for (int ip = 0; ip < met->np; ip++)
11114 pows[ip] = pow(1000. / met->p[ip], 0.286);
11115
11116 /* Loop over grid points... */
11117#pragma omp parallel for default(shared)
11118 for (int ix = 0; ix < met->nx; ix++) {
11119
11120 /* Set indices... */
11121 const int ix0 = MAX(ix - 1, 0);
11122 const int ix1 = MIN(ix + 1, met->nx - 1);
11123
11124 /* Loop over grid points... */
11125 for (int iy = 0; iy < met->ny; iy++) {
11126
11127 /* Set indices... */
11128 const int iy0 = MAX(iy - 1, 0);
11129 const int iy1 = MIN(iy + 1, met->ny - 1);
11130
11131 /* Set auxiliary variables... */
11132 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
11133 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
11134 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
11135 const double c0 = cos(DEG2RAD(met->lat[iy0]));
11136 const double c1 = cos(DEG2RAD(met->lat[iy1]));
11137 const double cr = cos(DEG2RAD(latr));
11138 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
11139
11140 /* Loop over grid points... */
11141 for (int ip = 0; ip < met->np; ip++) {
11142
11143 /* Get gradients in longitude... */
11144 const double dtdx
11145 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
11146 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
11147
11148 /* Get gradients in latitude... */
11149 const double dtdy
11150 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
11151 const double dudy
11152 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
11153
11154 /* Set indices... */
11155 const int ip0 = MAX(ip - 1, 0);
11156 const int ip1 = MIN(ip + 1, met->np - 1);
11157
11158 /* Get gradients in pressure... */
11159 double dtdp, dudp, dvdp;
11160 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
11161 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
11162 if (ip != ip0 && ip != ip1) {
11163 double denom = dp0 * dp1 * (dp0 + dp1);
11164 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
11165 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
11166 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
11167 / denom;
11168 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
11169 - dp1 * dp1 * met->u[ix][iy][ip0]
11170 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
11171 / denom;
11172 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
11173 - dp1 * dp1 * met->v[ix][iy][ip0]
11174 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
11175 / denom;
11176 } else {
11177 const double denom = dp0 + dp1;
11178 dtdp =
11179 (met->t[ix][iy][ip1] * pows[ip1] -
11180 met->t[ix][iy][ip0] * pows[ip0]) / denom;
11181 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
11182 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
11183 }
11184
11185 /* Calculate PV... */
11186 met->pv[ix][iy][ip] = (float)
11187 (1e6 * G0 *
11188 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
11189 }
11190 }
11191 }
11192
11193 /* Fix for polar regions... */
11194#pragma omp parallel for default(shared)
11195 for (int ix = 0; ix < met->nx; ix++)
11196 for (int ip = 0; ip < met->np; ip++) {
11197 met->pv[ix][0][ip]
11198 = met->pv[ix][1][ip]
11199 = met->pv[ix][2][ip];
11200 met->pv[ix][met->ny - 1][ip]
11201 = met->pv[ix][met->ny - 2][ip]
11202 = met->pv[ix][met->ny - 3][ip];
11203 }
11204}
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:591
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:570

◆ 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 11208 of file mptrac.c.

11209 {
11210
11211 /* Set timer... */
11212 SELECT_TIMER("READ_MET_OZONE", "METPROC");
11213 LOG(2, "Calculate total column ozone...");
11214
11215 /* Loop over columns... */
11216#pragma omp parallel for default(shared) collapse(2)
11217 for (int ix = 0; ix < met->nx; ix++)
11218 for (int iy = 0; iy < met->ny; iy++) {
11219
11220 /* Integrate... */
11221 double cd = 0;
11222 for (int ip = 1; ip < met->np; ip++)
11223 if (met->p[ip - 1] <= met->ps[ix][iy]) {
11224 const double vmr =
11225 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
11226 const double dp = met->p[ip - 1] - met->p[ip];
11227 cd += vmr * MO3 / MA * dp * 1e2 / G0;
11228 }
11229
11230 /* Convert to Dobson units... */
11231 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
11232 }
11233}

◆ 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 11237 of file mptrac.c.

11239 {
11240
11241 met_t *help;
11242
11243 /* Check parameters... */
11244 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
11245 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
11246 return;
11247
11248 /* Set timer... */
11249 SELECT_TIMER("READ_MET_SAMPLE", "METPROC");
11250 LOG(2, "Downsampling of meteo data...");
11251
11252 /* Allocate... */
11253 ALLOC(help, met_t, 1);
11254
11255 /* Copy data... */
11256 help->nx = met->nx;
11257 help->ny = met->ny;
11258 help->np = met->np;
11259 memcpy(help->lon, met->lon, sizeof(met->lon));
11260 memcpy(help->lat, met->lat, sizeof(met->lat));
11261 memcpy(help->p, met->p, sizeof(met->p));
11262
11263 /* Smoothing... */
11264 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
11265 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
11266 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
11267 help->ps[ix][iy] = 0;
11268 help->zs[ix][iy] = 0;
11269 help->ts[ix][iy] = 0;
11270 help->us[ix][iy] = 0;
11271 help->vs[ix][iy] = 0;
11272 help->ess[ix][iy] = 0;
11273 help->nss[ix][iy] = 0;
11274 help->shf[ix][iy] = 0;
11275 help->lsm[ix][iy] = 0;
11276 help->sst[ix][iy] = 0;
11277 help->pbl[ix][iy] = 0;
11278 help->cape[ix][iy] = 0;
11279 help->cin[ix][iy] = 0;
11280 help->t[ix][iy][ip] = 0;
11281 help->u[ix][iy][ip] = 0;
11282 help->v[ix][iy][ip] = 0;
11283 help->w[ix][iy][ip] = 0;
11284 help->h2o[ix][iy][ip] = 0;
11285 help->o3[ix][iy][ip] = 0;
11286 help->lwc[ix][iy][ip] = 0;
11287 help->rwc[ix][iy][ip] = 0;
11288 help->iwc[ix][iy][ip] = 0;
11289 help->swc[ix][iy][ip] = 0;
11290 help->cc[ix][iy][ip] = 0;
11291 float wsum = 0;
11292 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
11293 ix2++) {
11294 int ix3 = ix2;
11295 if (ix3 < 0)
11296 ix3 += met->nx;
11297 else if (ix3 >= met->nx)
11298 ix3 -= met->nx;
11299
11300 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
11301 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
11302 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
11303 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
11304 const float w =
11305 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
11306 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
11307 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
11308 help->ps[ix][iy] += w * met->ps[ix3][iy2];
11309 help->zs[ix][iy] += w * met->zs[ix3][iy2];
11310 help->ts[ix][iy] += w * met->ts[ix3][iy2];
11311 help->us[ix][iy] += w * met->us[ix3][iy2];
11312 help->vs[ix][iy] += w * met->vs[ix3][iy2];
11313 help->ess[ix][iy] += w * met->ess[ix3][iy2];
11314 help->nss[ix][iy] += w * met->nss[ix3][iy2];
11315 help->shf[ix][iy] += w * met->shf[ix3][iy2];
11316 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
11317 help->sst[ix][iy] += w * met->sst[ix3][iy2];
11318 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
11319 help->cape[ix][iy] += w * met->cape[ix3][iy2];
11320 help->cin[ix][iy] += w * met->cin[ix3][iy2];
11321 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
11322 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
11323 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
11324 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
11325 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
11326 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
11327 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
11328 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
11329 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
11330 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
11331 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
11332 wsum += w;
11333 }
11334 }
11335 help->ps[ix][iy] /= wsum;
11336 help->zs[ix][iy] /= wsum;
11337 help->ts[ix][iy] /= wsum;
11338 help->us[ix][iy] /= wsum;
11339 help->vs[ix][iy] /= wsum;
11340 help->ess[ix][iy] /= wsum;
11341 help->nss[ix][iy] /= wsum;
11342 help->shf[ix][iy] /= wsum;
11343 help->lsm[ix][iy] /= wsum;
11344 help->sst[ix][iy] /= wsum;
11345 help->pbl[ix][iy] /= wsum;
11346 help->cape[ix][iy] /= wsum;
11347 help->cin[ix][iy] /= wsum;
11348 help->t[ix][iy][ip] /= wsum;
11349 help->u[ix][iy][ip] /= wsum;
11350 help->v[ix][iy][ip] /= wsum;
11351 help->w[ix][iy][ip] /= wsum;
11352 help->h2o[ix][iy][ip] /= wsum;
11353 help->o3[ix][iy][ip] /= wsum;
11354 help->lwc[ix][iy][ip] /= wsum;
11355 help->rwc[ix][iy][ip] /= wsum;
11356 help->iwc[ix][iy][ip] /= wsum;
11357 help->swc[ix][iy][ip] /= wsum;
11358 help->cc[ix][iy][ip] /= wsum;
11359 }
11360 }
11361 }
11362
11363 /* Downsampling... */
11364 met->nx = 0;
11365 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
11366 met->lon[met->nx] = help->lon[ix];
11367 met->ny = 0;
11368 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
11369 met->lat[met->ny] = help->lat[iy];
11370 met->ps[met->nx][met->ny] = help->ps[ix][iy];
11371 met->zs[met->nx][met->ny] = help->zs[ix][iy];
11372 met->ts[met->nx][met->ny] = help->ts[ix][iy];
11373 met->us[met->nx][met->ny] = help->us[ix][iy];
11374 met->vs[met->nx][met->ny] = help->vs[ix][iy];
11375 met->ess[met->nx][met->ny] = help->ess[ix][iy];
11376 met->nss[met->nx][met->ny] = help->nss[ix][iy];
11377 met->shf[met->nx][met->ny] = help->shf[ix][iy];
11378 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
11379 met->sst[met->nx][met->ny] = help->sst[ix][iy];
11380 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
11381 met->cape[met->nx][met->ny] = help->cape[ix][iy];
11382 met->cin[met->nx][met->ny] = help->cin[ix][iy];
11383 met->np = 0;
11384 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
11385 met->p[met->np] = help->p[ip];
11386 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
11387 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
11388 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
11389 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
11390 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
11391 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
11392 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
11393 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
11394 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
11395 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
11396 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
11397 met->np++;
11398 }
11399 met->ny++;
11400 }
11401 met->nx++;
11402 }
11403
11404 /* Free... */
11405 free(help);
11406}

◆ 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 11410 of file mptrac.c.

11413 {
11414
11415 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
11416 th2[200], z[EP], z2[200];
11417
11418 /* Set timer... */
11419 SELECT_TIMER("READ_MET_TROPO", "METPROC");
11420 LOG(2, "Calculate tropopause...");
11421
11422 /* Get altitude and pressure profiles... */
11423#pragma omp parallel for default(shared)
11424 for (int iz = 0; iz < met->np; iz++)
11425 z[iz] = Z(met->p[iz]);
11426#pragma omp parallel for default(shared)
11427 for (int iz = 0; iz <= 190; iz++) {
11428 z2[iz] = 4.5 + 0.1 * iz;
11429 p2[iz] = P(z2[iz]);
11430 }
11431
11432 /* Do not calculate tropopause... */
11433 if (ctl->met_tropo == 0)
11434#pragma omp parallel for default(shared) collapse(2)
11435 for (int ix = 0; ix < met->nx; ix++)
11436 for (int iy = 0; iy < met->ny; iy++)
11437 met->pt[ix][iy] = NAN;
11438
11439 /* Use tropopause climatology... */
11440 else if (ctl->met_tropo == 1) {
11441#pragma omp parallel for default(shared) collapse(2)
11442 for (int ix = 0; ix < met->nx; ix++)
11443 for (int iy = 0; iy < met->ny; iy++)
11444 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
11445 }
11446
11447 /* Use cold point... */
11448 else if (ctl->met_tropo == 2) {
11449
11450 /* Loop over grid points... */
11451#pragma omp parallel for default(shared) private(t,t2) collapse(2)
11452 for (int ix = 0; ix < met->nx; ix++)
11453 for (int iy = 0; iy < met->ny; iy++) {
11454
11455 /* Interpolate temperature profile... */
11456 for (int iz = 0; iz < met->np; iz++)
11457 t[iz] = met->t[ix][iy][iz];
11458 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
11459
11460 /* Find minimum... */
11461 int iz = (int) gsl_stats_min_index(t2, 1, 171);
11462 if (iz > 0 && iz < 170)
11463 met->pt[ix][iy] = (float) p2[iz];
11464 else
11465 met->pt[ix][iy] = NAN;
11466 }
11467 }
11468
11469 /* Use WMO definition... */
11470 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
11471
11472 /* Loop over grid points... */
11473#pragma omp parallel for default(shared) private(t,t2) collapse(2)
11474 for (int ix = 0; ix < met->nx; ix++)
11475 for (int iy = 0; iy < met->ny; iy++) {
11476
11477 /* Interpolate temperature profile... */
11478 int iz;
11479 for (iz = 0; iz < met->np; iz++)
11480 t[iz] = met->t[ix][iy][iz];
11481 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
11482
11483 /* Find 1st tropopause... */
11484 met->pt[ix][iy] = NAN;
11485 for (iz = 0; iz <= 170; iz++) {
11486 int found = 1;
11487 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
11488 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
11489 found = 0;
11490 break;
11491 }
11492 if (found) {
11493 if (iz > 0 && iz < 170)
11494 met->pt[ix][iy] = (float) p2[iz];
11495 break;
11496 }
11497 }
11498
11499 /* Find 2nd tropopause... */
11500 if (ctl->met_tropo == 4) {
11501 met->pt[ix][iy] = NAN;
11502 for (; iz <= 170; iz++) {
11503 int found = 1;
11504 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
11505 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
11506 found = 0;
11507 break;
11508 }
11509 if (found)
11510 break;
11511 }
11512 for (; iz <= 170; iz++) {
11513 int found = 1;
11514 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
11515 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
11516 found = 0;
11517 break;
11518 }
11519 if (found) {
11520 if (iz > 0 && iz < 170)
11521 met->pt[ix][iy] = (float) p2[iz];
11522 break;
11523 }
11524 }
11525 }
11526 }
11527 }
11528
11529 /* Use dynamical tropopause... */
11530 else if (ctl->met_tropo == 5) {
11531
11532 /* Loop over grid points... */
11533#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
11534 for (int ix = 0; ix < met->nx; ix++)
11535 for (int iy = 0; iy < met->ny; iy++) {
11536
11537 /* Interpolate potential vorticity profile... */
11538 for (int iz = 0; iz < met->np; iz++)
11539 pv[iz] = met->pv[ix][iy][iz];
11540 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
11541
11542 /* Interpolate potential temperature profile... */
11543 for (int iz = 0; iz < met->np; iz++)
11544 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
11545 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
11546
11547 /* Find dynamical tropopause... */
11548 met->pt[ix][iy] = NAN;
11549 for (int iz = 0; iz <= 170; iz++)
11550 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
11551 || th2[iz] >= ctl->met_tropo_theta) {
11552 if (iz > 0 && iz < 170)
11553 met->pt[ix][iy] = (float) p2[iz];
11554 break;
11555 }
11556 }
11557 }
11558
11559 else
11560 ERRMSG("Cannot calculate tropopause!");
11561
11562 /* Interpolate temperature, geopotential height, and water vapor... */
11563#pragma omp parallel for default(shared) collapse(2)
11564 for (int ix = 0; ix < met->nx; ix++)
11565 for (int iy = 0; iy < met->ny; iy++) {
11566 double h2ot, tt, zt;
11568 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
11569 met->lat[iy], &tt, ci, cw, 1);
11570 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
11571 met->lat[iy], &zt, ci, cw, 0);
11572 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
11573 met->lat[iy], &h2ot, ci, cw, 0);
11574 met->tt[ix][iy] = (float) tt;
11575 met->zt[ix][iy] = (float) zt;
11576 met->h2ot[ix][iy] = (float) h2ot;
11577 }
11578}
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:11788
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:1036
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 11582 of file mptrac.c.

11590 {
11591
11592 /* Write info... */
11593 LOG(1, "Read observation data: %s", filename);
11594
11595 /* Read data... */
11596 if (ctl->obs_type == 0)
11597 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
11598 else if (ctl->obs_type == 1)
11599 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
11600 else
11601 ERRMSG("Set OBS_TYPE to 0 or 1!");
11602
11603 /* Check time... */
11604 for (int i = 1; i < *nobs; i++)
11605 if (rt[i] < rt[i - 1])
11606 ERRMSG("Time must be ascending!");
11607
11608 /* Write info... */
11609 int n = *nobs;
11610 double mini, maxi;
11611 LOG(2, "Number of observations: %d", *nobs);
11612 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
11613 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
11614 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
11615 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
11616 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
11617 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
11618 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
11619 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
11620 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
11621 LOG(2, "Observation range: %g ... %g", mini, maxi);
11622}
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:11626
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:11654
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 11626 of file mptrac.c.

11633 {
11634
11635 /* Open observation data file... */
11636 FILE *in;
11637 if (!(in = fopen(filename, "r")))
11638 ERRMSG("Cannot open file!");
11639
11640 /* Read observations... */
11641 char line[LEN];
11642 while (fgets(line, LEN, in))
11643 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
11644 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
11645 if ((++(*nobs)) >= NOBS)
11646 ERRMSG("Too many observations!");
11647
11648 /* Close observation data file... */
11649 fclose(in);
11650}
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:379

◆ 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 11654 of file mptrac.c.

11661 {
11662
11663 int ncid, varid;
11664
11665 /* Open netCDF file... */
11666 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
11667 ERRMSG("Cannot open file!");
11668
11669 /* Read the observations from the NetCDF file... */
11670 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
11671 NC_GET_DOUBLE("time", rt, 1);
11672 NC_GET_DOUBLE("alt", rz, 1);
11673 NC_GET_DOUBLE("lon", rlon, 1);
11674 NC_GET_DOUBLE("lat", rlat, 1);
11675 NC_GET_DOUBLE("obs", robs, 1);
11676
11677 /* Close file... */
11678 NC(nc_close(ncid));
11679}

◆ 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 11683 of file mptrac.c.

11690 {
11691
11692 FILE *in = NULL;
11693
11694 char fullname1[LEN], fullname2[LEN], rval[LEN];
11695
11696 int contain = 0, i;
11697
11698 /* Open file... */
11699 if (filename[strlen(filename) - 1] != '-')
11700 if (!(in = fopen(filename, "r")))
11701 ERRMSG("Cannot open file!");
11702
11703 /* Set full variable name... */
11704 if (arridx >= 0) {
11705 sprintf(fullname1, "%s[%d]", varname, arridx);
11706 sprintf(fullname2, "%s[*]", varname);
11707 } else {
11708 sprintf(fullname1, "%s", varname);
11709 sprintf(fullname2, "%s", varname);
11710 }
11711
11712 /* Read data... */
11713 if (in != NULL) {
11714 char dummy[LEN], line[LEN], rvarname[LEN];
11715 while (fgets(line, LEN, in)) {
11716 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
11717 if (strcasecmp(rvarname, fullname1) == 0 ||
11718 strcasecmp(rvarname, fullname2) == 0) {
11719 contain = 1;
11720 break;
11721 }
11722 }
11723 }
11724 for (i = 1; i < argc - 1; i++)
11725 if (strcasecmp(argv[i], fullname1) == 0 ||
11726 strcasecmp(argv[i], fullname2) == 0) {
11727 sprintf(rval, "%s", argv[i + 1]);
11728 contain = 1;
11729 break;
11730 }
11731
11732 /* Close file... */
11733 if (in != NULL)
11734 fclose(in);
11735
11736 /* Check for missing variables... */
11737 if (!contain) {
11738 if (strlen(defvalue) > 0)
11739 sprintf(rval, "%s", defvalue);
11740 else
11741 ERRMSG("Missing variable %s!\n", fullname1);
11742 }
11743
11744 /* Write info... */
11745 LOG(1, "%s = %s", fullname1, rval);
11746
11747 /* Return values... */
11748 if (value != NULL)
11749 sprintf(value, "%s", rval);
11750 return atof(rval);
11751}

◆ 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 11755 of file mptrac.c.

11759 {
11760
11761 /* Convert particle radius from microns to m... */
11762 const double rp_help = rp * 1e-6;
11763
11764 /* Density of dry air [kg / m^3]... */
11765 const double rho = RHO(p, T);
11766
11767 /* Dynamic viscosity of air [kg / (m s)]... */
11768 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
11769
11770 /* Thermal velocity of an air molecule [m / s]... */
11771 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
11772
11773 /* Mean free path of an air molecule [m]... */
11774 const double lambda = 2. * eta / (rho * v);
11775
11776 /* Knudsen number for air (dimensionless)... */
11777 const double K = lambda / rp_help;
11778
11779 /* Cunningham slip-flow correction (dimensionless)... */
11780 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
11781
11782 /* Sedimentation velocity [m / s]... */
11783 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
11784}
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:285

◆ 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 11788 of file mptrac.c.

11795 {
11796
11797 /* Cubic spline interpolation... */
11798 if (method == 1) {
11799
11800 /* Allocate... */
11801 gsl_interp_accel *acc = gsl_interp_accel_alloc();
11802 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
11803
11804 /* Interpolate profile... */
11805 gsl_spline_init(s, x, y, (size_t) n);
11806 for (int i = 0; i < n2; i++)
11807 if (x2[i] <= x[0])
11808 y2[i] = y[0];
11809 else if (x2[i] >= x[n - 1])
11810 y2[i] = y[n - 1];
11811 else
11812 y2[i] = gsl_spline_eval(s, x2[i], acc);
11813
11814 /* Free... */
11815 gsl_spline_free(s);
11816 gsl_interp_accel_free(acc);
11817 }
11818
11819 /* Linear interpolation... */
11820 else {
11821 for (int i = 0; i < n2; i++)
11822 if (x2[i] <= x[0])
11823 y2[i] = y[0];
11824 else if (x2[i] >= x[n - 1])
11825 y2[i] = y[n - 1];
11826 else {
11827 const int idx = locate_irr(x, n, x2[i]);
11828 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
11829 }
11830 }
11831}
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 11835 of file mptrac.c.

11837 {
11838
11839 if (n <= 0)
11840 return 0;
11841
11842 float mean = 0, var = 0;
11843
11844 for (int i = 0; i < n; ++i) {
11845 mean += data[i];
11846 var += SQR(data[i]);
11847 }
11848
11849 var = var / (float) n - SQR(mean / (float) n);
11850
11851 return (var > 0 ? sqrtf(var) : 0);
11852}

◆ 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 11856 of file mptrac.c.

11864 {
11865
11866 struct tm t0, t1;
11867
11868 t0.tm_year = 100;
11869 t0.tm_mon = 0;
11870 t0.tm_mday = 1;
11871 t0.tm_hour = 0;
11872 t0.tm_min = 0;
11873 t0.tm_sec = 0;
11874
11875 t1.tm_year = year - 1900;
11876 t1.tm_mon = mon - 1;
11877 t1.tm_mday = day;
11878 t1.tm_hour = hour;
11879 t1.tm_min = min;
11880 t1.tm_sec = sec;
11881
11882 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
11883}

◆ 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 11887 of file mptrac.c.

11890 {
11891
11892 static char names[NTIMER][100], groups[NTIMER][100];
11893
11894 static double rt_name[NTIMER], rt_group[NTIMER],
11895 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
11896
11897 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
11898
11899 /* Get time... */
11900 t1 = omp_get_wtime();
11901 dt = t1 - t0;
11902
11903 /* Add elapsed time to current timers... */
11904 if (iname >= 0) {
11905 rt_name[iname] += dt;
11906 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
11907 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
11908 ct_name[iname]++;
11909 }
11910 if (igroup >= 0)
11911 rt_group[igroup] += t1 - t0;
11912
11913 /* Report timers... */
11914 if (output) {
11915 for (int i = 0; i < nname; i++)
11916 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
11917 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
11918 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
11919 for (int i = 0; i < ngroup; i++)
11920 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
11921 double total = 0.0;
11922 for (int i = 0; i < nname; i++)
11923 total += rt_name[i];
11924 LOG(1, "TIMER_TOTAL = %.3f s", total);
11925 }
11926
11927 /* Identify IDs of next timer... */
11928 for (iname = 0; iname < nname; iname++)
11929 if (strcasecmp(name, names[iname]) == 0)
11930 break;
11931 for (igroup = 0; igroup < ngroup; igroup++)
11932 if (strcasecmp(group, groups[igroup]) == 0)
11933 break;
11934
11935 /* Check whether this is a new timer... */
11936 if (iname >= nname) {
11937 sprintf(names[iname], "%s", name);
11938 if ((++nname) >= NTIMER)
11939 ERRMSG("Too many timers!");
11940 }
11941
11942 /* Check whether this is a new group... */
11943 if (igroup >= ngroup) {
11944 sprintf(groups[igroup], "%s", group);
11945 if ((++ngroup) >= NTIMER)
11946 ERRMSG("Too many groups!");
11947 }
11948
11949 /* Save starting time... */
11950 t0 = t1;
11951}
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2154

◆ time_from_filename()

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

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.
Returns
The time in Julian seconds as a double.

The function performs the following steps:

  • Extracts the year, month, day, hour, and minute 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 format of the timestamp in the filename is YYYY-MM-DD_HH-MM (e.g., "2023-05-27_14-45").
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 11955 of file mptrac.c.

11957 {
11958
11959 char tstr[10];
11960
11961 double t;
11962
11963 /* Get time from filename... */
11964 int len = (int) strlen(filename);
11965 sprintf(tstr, "%.4s", &filename[len - offset]);
11966 int year = atoi(tstr);
11967 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
11968 int mon = atoi(tstr);
11969 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
11970 int day = atoi(tstr);
11971 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
11972 int hour = atoi(tstr);
11973 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
11974 int min = atoi(tstr);
11975
11976 /* Check time... */
11977 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
11978 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
11979 ERRMSG("Cannot read time from filename!");
11980
11981 /* Convert time to Julian seconds... */
11982 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
11983
11984 /* Return time... */
11985 return t;
11986}
Here is the call graph for this function:

◆ tropo_weight()

double tropo_weight ( 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]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 11990 of file mptrac.c.

11993 {
11994
11995 /* Get tropopause pressure... */
11996 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
11997
11998 /* Get pressure range... */
11999 const double p1 = pt * 0.866877899;
12000 const double p0 = pt / 0.866877899;
12001
12002 /* Get weighting factor... */
12003 if (atm->p[ip] > p0)
12004 return 1;
12005 else if (atm->p[ip] < p1)
12006 return 0;
12007 else
12008 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
12009}
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 12013 of file mptrac.c.

12017 {
12018
12019 FILE *out;
12020
12021 /* Set time interval for output... */
12022 const double t0 = t - 0.5 * ctl->dt_mod;
12023 const double t1 = t + 0.5 * ctl->dt_mod;
12024
12025 /* Check if gnuplot output is requested... */
12026 if (ctl->atm_gpfile[0] != '-') {
12027
12028 /* Create gnuplot pipe... */
12029 if (!(out = popen("gnuplot", "w")))
12030 ERRMSG("Cannot create pipe to gnuplot!");
12031
12032 /* Set plot filename... */
12033 fprintf(out, "set out \"%s.png\"\n", filename);
12034
12035 /* Set time string... */
12036 double r;
12037 int year, mon, day, hour, min, sec;
12038 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12039 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12040 year, mon, day, hour, min);
12041
12042 /* Dump gnuplot file to pipe... */
12043 FILE *in;
12044 if (!(in = fopen(ctl->atm_gpfile, "r")))
12045 ERRMSG("Cannot open file!");
12046 char line[LEN];
12047 while (fgets(line, LEN, in))
12048 fprintf(out, "%s", line);
12049 fclose(in);
12050 }
12051
12052 else {
12053
12054 /* Create file... */
12055 if (!(out = fopen(filename, "w")))
12056 ERRMSG("Cannot create file!");
12057 }
12058
12059 /* Write header... */
12060 fprintf(out,
12061 "# $1 = time [s]\n"
12062 "# $2 = altitude [km]\n"
12063 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12064 for (int iq = 0; iq < ctl->nq; iq++)
12065 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
12066 ctl->qnt_unit[iq]);
12067 fprintf(out, "\n");
12068
12069 /* Write data... */
12070 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
12071
12072 /* Check time... */
12073 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12074 continue;
12075
12076 /* Write output... */
12077 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
12078 atm->lon[ip], atm->lat[ip]);
12079 for (int iq = 0; iq < ctl->nq; iq++) {
12080 fprintf(out, " ");
12081 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12082 fprintf(out, ctl->qnt_format[iq], NAN);
12083 else
12084 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
12085 }
12086 fprintf(out, "\n");
12087 }
12088
12089 /* Close file... */
12090 fclose(out);
12091}
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 12095 of file mptrac.c.

12098 {
12099
12100 FILE *out;
12101
12102 /* Create file... */
12103 if (!(out = fopen(filename, "w")))
12104 ERRMSG("Cannot create file!");
12105
12106 /* Write version of binary data... */
12107 int version = 100;
12108 FWRITE(&version, int,
12109 1,
12110 out);
12111
12112 /* Write data... */
12113 FWRITE(&atm->np, int,
12114 1,
12115 out);
12116 FWRITE(atm->time, double,
12117 (size_t) atm->np,
12118 out);
12119 FWRITE(atm->p, double,
12120 (size_t) atm->np,
12121 out);
12122 FWRITE(atm->lon, double,
12123 (size_t) atm->np,
12124 out);
12125 FWRITE(atm->lat, double,
12126 (size_t) atm->np,
12127 out);
12128 for (int iq = 0; iq < ctl->nq; iq++)
12129 FWRITE(atm->q[iq], double,
12130 (size_t) atm->np,
12131 out);
12132
12133 /* Write final flag... */
12134 int final = 999;
12135 FWRITE(&final, int,
12136 1,
12137 out);
12138
12139 /* Close file... */
12140 fclose(out);
12141}

◆ 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 12145 of file mptrac.c.

12148 {
12149
12150 int tid, pid, ncid, varid;
12151 size_t start[2], count[2];
12152
12153 /* Create file... */
12154 NC(nc_create(filename, NC_NETCDF4, &ncid));
12155
12156 /* Define dimensions... */
12157 NC(nc_def_dim(ncid, "time", 1, &tid));
12158 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12159
12160 /* Define variables and their attributes... */
12161 int dim_ids[2] = { tid, pid };
12162 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12163 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12164 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
12165 ctl->atm_nc_level, 0);
12166 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
12167 ctl->atm_nc_level, 0);
12168 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
12169 ctl->atm_nc_level, 0);
12170 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
12171 for (int iq = 0; iq < ctl->nq; iq++)
12172 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12173 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12174 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12175
12176 /* Define global attributes... */
12177 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12178 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12179
12180 /* End definitions... */
12181 NC(nc_enddef(ncid));
12182
12183 /* Write data... */
12184 NC_PUT_DOUBLE("time", atm->time, 0);
12185 NC_PUT_DOUBLE("LAT", atm->lat, 0);
12186 NC_PUT_DOUBLE("LON", atm->lon, 0);
12187 NC_PUT_DOUBLE("PRESS", atm->p, 0);
12188 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
12189 for (int iq = 0; iq < ctl->nq; iq++)
12190 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12191
12192 /* Close file... */
12193 NC(nc_close(ncid));
12194}
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1411
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1241
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1325

◆ 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 12198 of file mptrac.c.

12202 {
12203
12204 /* Global Counter... */
12205 static size_t out_cnt = 0;
12206
12207 double r, r_start, r_stop;
12208 int year, mon, day, hour, min, sec;
12209 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
12210 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
12211 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
12212
12213 int ncid, varid, tid, pid, cid;
12214 int dim_ids[2];
12215
12216 /* time, nparc */
12217 size_t start[2];
12218 size_t count[2];
12219
12220 /* Determine start and stop times of calculation... */
12221 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12222 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
12223 &min_start, &sec_start, &r_start);
12224 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
12225 &min_stop, &sec_stop, &r_stop);
12226
12227 sprintf(filename_out,
12228 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
12229 year_start % 100, mon_start, day_start, hour_start,
12230 year_stop % 100, mon_stop, day_stop, hour_stop);
12231 LOG(1, "Write traj file: %s", filename_out);
12232
12233 /* Define hyperslap for the traj_file... */
12234 start[0] = out_cnt;
12235 start[1] = 0;
12236 count[0] = 1;
12237 count[1] = (size_t) atm->np;
12238
12239 /* Create the file at the first timestep... */
12240 if (out_cnt == 0) {
12241
12242 /* Create file... */
12243 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
12244
12245 /* Define dimensions... */
12246 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
12247 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12248 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
12249 dim_ids[0] = tid;
12250 dim_ids[1] = pid;
12251
12252 /* Define variables and their attributes... */
12253 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12254 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12255 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
12256 ctl->atm_nc_level, 0);
12257 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
12258 ctl->atm_nc_level, 0);
12259 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
12260 ctl->atm_nc_level, 0);
12261 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
12262 ctl->atm_nc_level, 0);
12263 for (int iq = 0; iq < ctl->nq; iq++)
12264 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12265 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12266 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12267
12268 /* Define global attributes... */
12269 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12270 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12271
12272 /* End definitions... */
12273 NC(nc_enddef(ncid));
12274 NC(nc_close(ncid));
12275 }
12276
12277 /* Increment global counter to change hyperslap... */
12278 out_cnt++;
12279
12280 /* Open file... */
12281 NC(nc_open(filename_out, NC_WRITE, &ncid));
12282
12283 /* Write data... */
12284 NC_PUT_DOUBLE("time", atm->time, 1);
12285 NC_PUT_DOUBLE("LAT", atm->lat, 1);
12286 NC_PUT_DOUBLE("LON", atm->lon, 1);
12287 NC_PUT_DOUBLE("PRESS", atm->p, 1);
12288 if (ctl->advect_vert_coord == 1) {
12289 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
12290 } else if (ctl->qnt_zeta >= 0) {
12291 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
12292 }
12293 for (int iq = 0; iq < ctl->nq; iq++)
12294 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
12295
12296 /* Close file... */
12297 NC(nc_close(ncid));
12298
12299 /* At the last time step create the init_fix_YYYYMMDDHH file... */
12300 if ((year == year_stop) && (mon == mon_stop)
12301 && (day == day_stop) && (hour == hour_stop)) {
12302
12303 /* Set filename... */
12304 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
12305 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
12306 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
12307 LOG(1, "Write init file: %s", filename_init);
12308
12309 /* Create file... */
12310 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
12311
12312 /* Define dimensions... */
12313 NC(nc_def_dim(ncid, "time", 1, &tid));
12314 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12315 dim_ids[0] = tid;
12316 dim_ids[1] = pid;
12317
12318 /* Define variables and their attributes... */
12319 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12320 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12321 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
12322 ctl->atm_nc_level, 0);
12323 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
12324 ctl->atm_nc_level, 0);
12325 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
12326 ctl->atm_nc_level, 0);
12327 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
12328 for (int iq = 0; iq < ctl->nq; iq++)
12329 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12330 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12331 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12332
12333 /* Define global attributes... */
12334 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12335 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12336
12337 /* End definitions... */
12338 NC(nc_enddef(ncid));
12339
12340 /* Write data... */
12341 NC_PUT_DOUBLE("time", atm->time, 0);
12342 NC_PUT_DOUBLE("LAT", atm->lat, 0);
12343 NC_PUT_DOUBLE("LON", atm->lon, 0);
12344 NC_PUT_DOUBLE("PRESS", atm->p, 0);
12345 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
12346 for (int iq = 0; iq < ctl->nq; iq++)
12347 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12348
12349 /* Close file... */
12350 NC(nc_close(ncid));
12351 }
12352}
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 12356 of file mptrac.c.

12359 {
12360
12361 int ncid, obsid, varid;
12362
12363 size_t start[2], count[2];
12364
12365 /* Create file... */
12366 NC(nc_create(filename, NC_NETCDF4, &ncid));
12367
12368 /* Define dimensions... */
12369 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
12370
12371 /* Define variables and their attributes... */
12372 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
12373 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12374 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
12375 ctl->atm_nc_level, 0);
12376 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
12377 ctl->atm_nc_level, 0);
12378 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
12379 ctl->atm_nc_level, 0);
12380 for (int iq = 0; iq < ctl->nq; iq++)
12381 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
12382 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
12383 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12384
12385 /* Define global attributes... */
12386 NC_PUT_ATT_GLOBAL("featureType", "point");
12387
12388 /* End definitions... */
12389 NC(nc_enddef(ncid));
12390
12391 /* Write data... */
12392 NC_PUT_DOUBLE("time", atm->time, 0);
12393 NC_PUT_DOUBLE("press", atm->p, 0);
12394 NC_PUT_DOUBLE("lon", atm->lon, 0);
12395 NC_PUT_DOUBLE("lat", atm->lat, 0);
12396 for (int iq = 0; iq < ctl->nq; iq++)
12397 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12398
12399 /* Close file... */
12400 NC(nc_close(ncid));
12401}

◆ 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 12405 of file mptrac.c.

12409 {
12410
12411 static FILE *out;
12412
12413 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
12414 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
12415
12416 static int *obscount, nobs, nk;
12417
12418 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
12419
12420 const int ensemble = (ctl->nens > 0);
12421
12422 /* Set timer */
12423 SELECT_TIMER("WRITE_CSI", "OUTPUT");
12424
12425 /* Check quantities... */
12426 if (ctl->qnt_m < 0)
12427 ERRMSG("Need quantity mass!");
12428 if (ensemble) {
12429 if (ctl->qnt_ens < 0)
12430 ERRMSG("Missing ensemble IDs!");
12431 if (ctl->nens > NENS)
12432 ERRMSG("Too many ensembles!");
12433 }
12434
12435 /* Init... */
12436 if (t == ctl->t_start) {
12437
12438 /* Allocate.. */
12439 ALLOC(area, double,
12440 ctl->csi_ny);
12441 ALLOC(rt, double,
12442 NOBS);
12443 ALLOC(rz, double,
12444 NOBS);
12445 ALLOC(rlon, double,
12446 NOBS);
12447 ALLOC(rlat, double,
12448 NOBS);
12449 ALLOC(robs, double,
12450 NOBS);
12451
12452 /* Read observation data... */
12453 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12454
12455 /* Read kernel data... */
12456 if (ctl->csi_kernel[0] != '-')
12457 read_kernel(ctl->csi_kernel, kz, kw, &nk);
12458
12459 /* Create new file... */
12460 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
12461 if (!(out = fopen(filename, "w")))
12462 ERRMSG("Cannot create file!");
12463
12464 /* Write header... */
12465 fprintf(out,
12466 "# $1 = time [s]\n"
12467 "# $2 = ensemble ID\n"
12468 "# $3 = number of hits (cx)\n"
12469 "# $4 = number of misses (cy)\n"
12470 "# $5 = number of false alarms (cz)\n"
12471 "# $6 = number of observations (cx + cy)\n"
12472 "# $7 = number of forecasts (cx + cz)\n"
12473 "# $8 = bias (%%)\n"
12474 "# $9 = POD (%%)\n"
12475 "# $10 = FAR (%%)\n"
12476 "# $11 = CSI (%%)\n"
12477 "# $12 = hits by random chance\n"
12478 "# $13 = ETS (%%)\n"
12479 "# $14 = Pearson R\n"
12480 "# $15 = Spearman R\n"
12481 "# $16 = mean error [kg/m²]\n"
12482 "# $17 = RMSE [kg/m²]\n"
12483 "# $18 = MAE [kg/m²]\n"
12484 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
12485
12486 /* Set grid box size... */
12487 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
12488 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
12489 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
12490
12491 /* Set horizontal coordinates... */
12492 for (int iy = 0; iy < ctl->csi_ny; iy++) {
12493 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
12494 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
12495 }
12496 }
12497
12498 /* Set time interval... */
12499 const double t0 = t - 0.5 * ctl->dt_mod;
12500 const double t1 = t + 0.5 * ctl->dt_mod;
12501
12502 /* Allocate... */
12503 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
12504 ALLOC(modmean, double,
12505 (ensemble ? ctl->nens : 1) * grid_size);
12506 ALLOC(obsmean, double,
12507 grid_size);
12508 ALLOC(obscount, int,
12509 grid_size);
12510 ALLOC(obsstd, double,
12511 grid_size);
12512
12513 /* Init... */
12514 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
12515 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
12516
12517 /* Loop over observations... */
12518 for (int i = 0; i < nobs; i++) {
12519 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
12520 continue;
12521
12522 /* Calculate indices... */
12523 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
12524 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
12525 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
12526 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
12527 || iz >= ctl->csi_nz)
12528 continue;
12529
12530 /* Get mean observation index... */
12531 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
12532 obsmean[idx] += robs[i];
12533 obsstd[idx] += SQR(robs[i]);
12534 obscount[idx]++;
12535 }
12536
12537 /* Analyze model data... */
12538 for (int ip = 0; ip < atm->np; ip++) {
12539
12540 /* Check time... */
12541 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12542 continue;
12543
12544 /* Get ensemble ID... */
12545 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
12546 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
12547 ERRMSG("Ensemble ID out of range!");
12548
12549 /* Get indices... */
12550 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
12551 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
12552 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
12553 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
12554 || iz >= ctl->csi_nz)
12555 continue;
12556
12557 /* Get total mass in grid cell... */
12558 const int idx =
12559 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
12560 modmean[idx] +=
12561 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
12562 }
12563 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
12564 /* Analyze all grid cells... */
12565 for (int ix = 0; ix < ctl->csi_nx; ix++)
12566 for (int iy = 0; iy < ctl->csi_ny; iy++)
12567 for (int iz = 0; iz < ctl->csi_nz; iz++) {
12568
12569 /* Calculate mean observation index... */
12570 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
12571 if (e == 0)
12572 if (obscount[idx]) {
12573 obsmean[idx] /= obscount[idx];
12574 obsstd[idx] =
12575 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
12576 }
12577
12578 /* Calculate model mean per ensemble... */
12579 const int midx = e * grid_size + idx;
12580 if (modmean[midx] > 0)
12581 modmean[midx] /= (1e6 * area[iy]);
12582
12583 /* Check number of observations... */
12584 if (obscount[idx]) {
12585
12586 /* Calculate CSI... */
12587 ct[e]++;
12588 if (obsmean[idx] >= ctl->csi_obsmin
12589 && modmean[midx] >= ctl->csi_modmin)
12590 cx[e]++;
12591 else if (obsmean[idx] >= ctl->csi_obsmin)
12592 cy[e]++;
12593 else if (modmean[midx] >= ctl->csi_modmin)
12594 cz[e]++;
12595
12596 /* Save data for other verification statistics... */
12597 if (obsmean[idx] >= ctl->csi_obsmin
12598 || modmean[midx] >= ctl->csi_modmin) {
12599 x[n[e]] = modmean[midx];
12600 y[n[e]] = obsmean[idx];
12601 if (modmean[midx] >= ctl->csi_modmin)
12602 obsstdn[n[e]] = obsstd[idx];
12603 if ((++n[e]) >= NCSI)
12604 ERRMSG("Too many points for statistics!");
12605 }
12606 }
12607 }
12608 /* Write output... */
12609 if (fmod(t, ctl->csi_dt_out) == 0) {
12610
12611 if (n[e] == 0)
12612 continue;
12613
12614 /* Calculate verification statistics
12615 (https://www.cawcr.gov.au/projects/verification/) ... */
12616 static double work[2 * NCSI], work2[2 * NCSI];
12617 const int n_obs = cx[e] + cy[e];
12618 const int n_for = cx[e] + cz[e];
12619 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
12620 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
12621 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
12622 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
12623 const double csi =
12624 (cx[e] + cy[e] + cz[e] >
12625 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
12626 const double ets =
12627 (cx[e] + cy[e] + cz[e] - cx_rd >
12628 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
12629 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
12630 const double rho_s =
12631 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
12632 for (int i = 0; i < n[e]; i++) {
12633 work[i] = x[i] - y[i];
12634 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
12635 }
12636 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
12637 const double rmse =
12638 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
12639 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
12640 const double loglikelihood =
12641 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
12642
12643 /* Write... */
12644 fprintf(out,
12645 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
12646 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
12647 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
12648 loglikelihood, n[e]);
12649
12650 /* Set counters to zero... */
12651 for (int i = 0; i < n[e]; i++)
12652 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
12653 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
12654 }
12655 }
12656 /* Free... */
12657 free(modmean);
12658 free(obsmean);
12659 free(obscount);
12660 free(obsstd);
12661
12662 /* Finalize... */
12663 if (t == ctl->t_stop) {
12664
12665 /* Close output file... */
12666 fclose(out);
12667
12668 /* Free... */
12669 free(area);
12670 free(rt);
12671 free(rz);
12672 free(rlon);
12673 free(rlat);
12674 free(robs);
12675 }
12676}
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:11582
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:8162
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:3220
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:374
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:369
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 12680 of file mptrac.c.

12684 {
12685
12686 static FILE *out;
12687
12688 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
12689 x[3], zm[NENS];
12690
12691 static int n[NENS];
12692
12693 /* Set timer... */
12694 SELECT_TIMER("WRITE_ENS", "OUTPUT");
12695
12696 /* Check quantities... */
12697 if (ctl->qnt_ens < 0)
12698 ERRMSG("Missing ensemble IDs!");
12699
12700 /* Set time interval... */
12701 const double t0 = t - 0.5 * ctl->dt_mod;
12702 const double t1 = t + 0.5 * ctl->dt_mod;
12703
12704 /* Init... */
12705 for (int i = 0; i < NENS; i++) {
12706 for (int iq = 0; iq < ctl->nq; iq++)
12707 qm[iq][i] = qs[iq][i] = 0;
12708 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
12709 n[i] = 0;
12710 }
12711
12712 /* Loop over air parcels... */
12713 for (int ip = 0; ip < atm->np; ip++) {
12714
12715 /* Check time... */
12716 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12717 continue;
12718
12719 /* Check ensemble ID... */
12720 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
12721 ERRMSG("Ensemble ID is out of range!");
12722
12723 /* Get means... */
12724 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
12725 for (int iq = 0; iq < ctl->nq; iq++) {
12726 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
12727 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
12728 }
12729 xm[ctl->qnt_ens][0] += x[0];
12730 xm[ctl->qnt_ens][1] += x[1];
12731 xm[ctl->qnt_ens][2] += x[2];
12732 zm[ctl->qnt_ens] += Z(atm->p[ip]);
12733 n[ctl->qnt_ens]++;
12734 }
12735
12736 /* Create file... */
12737 LOG(1, "Write ensemble data: %s", filename);
12738 if (!(out = fopen(filename, "w")))
12739 ERRMSG("Cannot create file!");
12740
12741 /* Write header... */
12742 fprintf(out,
12743 "# $1 = time [s]\n"
12744 "# $2 = altitude [km]\n"
12745 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12746 for (int iq = 0; iq < ctl->nq; iq++)
12747 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
12748 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12749 for (int iq = 0; iq < ctl->nq; iq++)
12750 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
12751 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12752 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
12753
12754 /* Write data... */
12755 for (int i = 0; i < NENS; i++)
12756 if (n[i] > 0) {
12757 cart2geo(xm[i], &dummy, &lon, &lat);
12758 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
12759 for (int iq = 0; iq < ctl->nq; iq++) {
12760 fprintf(out, " ");
12761 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
12762 }
12763 for (int iq = 0; iq < ctl->nq; iq++) {
12764 fprintf(out, " ");
12765 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
12766 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
12767 }
12768 fprintf(out, " %d\n", n[i]);
12769 }
12770
12771 /* Close file... */
12772 fclose(out);
12773}
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:72
Here is the call graph for this function:

◆ 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 12777 of file mptrac.c.

12783 {
12784
12785 static double kz[EP], kw[EP];
12786
12787 static int nk;
12788
12789 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
12790
12791 int *ixs, *iys, *izs, *np;
12792
12793 /* Set timer... */
12794 SELECT_TIMER("WRITE_GRID", "OUTPUT");
12795
12796 /* Write info... */
12797 LOG(1, "Write grid data: %s", filename);
12798
12799 /* Init... */
12800 if (t == ctl->t_start) {
12801
12802 /* Read kernel data... */
12803 if (ctl->grid_kernel[0] != '-')
12804 read_kernel(ctl->grid_kernel, kz, kw, &nk);
12805 }
12806
12807 /* Allocate... */
12808 ALLOC(cd, double,
12809 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12810 for (int iq = 0; iq < ctl->nq; iq++) {
12811 ALLOC(mean[iq], double,
12812 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12813 ALLOC(sigma[iq], double,
12814 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12815 }
12816 ALLOC(vmr_impl, double,
12817 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12818 ALLOC(z, double,
12819 ctl->grid_nz);
12820 ALLOC(lon, double,
12821 ctl->grid_nx);
12822 ALLOC(lat, double,
12823 ctl->grid_ny);
12824 ALLOC(area, double,
12825 ctl->grid_ny);
12826 ALLOC(press, double,
12827 ctl->grid_nz);
12828 ALLOC(np, int,
12829 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12830 ALLOC(ixs, int,
12831 atm->np);
12832 ALLOC(iys, int,
12833 atm->np);
12834 ALLOC(izs, int,
12835 atm->np);
12836
12837 /* Set grid box size... */
12838 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
12839 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
12840 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
12841
12842 /* Set vertical coordinates... */
12843#pragma omp parallel for default(shared)
12844 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12845 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
12846 press[iz] = P(z[iz]);
12847 }
12848
12849 /* Set horizontal coordinates... */
12850 for (int ix = 0; ix < ctl->grid_nx; ix++)
12851 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
12852#pragma omp parallel for default(shared)
12853 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12854 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
12855 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
12856 }
12857
12858 /* Set time interval for output... */
12859 const double t0 = t - 0.5 * ctl->dt_mod;
12860 const double t1 = t + 0.5 * ctl->dt_mod;
12861
12862 /* Get grid box indices... */
12863#pragma omp parallel for default(shared)
12864 for (int ip = 0; ip < atm->np; ip++) {
12865 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
12866 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
12867 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
12868 if (atm->time[ip] < t0 || atm->time[ip] > t1
12869 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
12870 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
12871 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
12872 izs[ip] = -1;
12873 }
12874
12875 /* Average data... */
12876 for (int ip = 0; ip < atm->np; ip++)
12877 if (izs[ip] >= 0) {
12878 const int idx =
12879 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
12880 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
12881 np[idx]++;
12882 for (int iq = 0; iq < ctl->nq; iq++) {
12883 mean[iq][idx] += kernel * atm->q[iq][ip];
12884 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
12885 }
12886 }
12887
12888 /* Calculate column density and volume mixing ratio... */
12889#pragma omp parallel for default(shared)
12890 for (int ix = 0; ix < ctl->grid_nx; ix++)
12891 for (int iy = 0; iy < ctl->grid_ny; iy++)
12892 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12893
12894 /* Get grid index... */
12895 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12896
12897 /* Calculate column density... */
12898 cd[idx] = NAN;
12899 if (ctl->qnt_m >= 0)
12900 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
12901
12902 /* Calculate volume mixing ratio (implicit)... */
12903 vmr_impl[idx] = NAN;
12904 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
12905 && met1 != NULL) {
12906 vmr_impl[idx] = 0;
12907 if (mean[ctl->qnt_m][idx] > 0) {
12908
12909 /* Get temperature... */
12910 double temp;
12912 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
12913 lon[ix], lat[iy], &temp, ci, cw, 1);
12914
12915 /* Calculate volume mixing ratio... */
12916 vmr_impl[idx] =
12917 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
12918 }
12919 }
12920
12921 /* Calculate mean... */
12922 if (np[idx] > 0)
12923 for (int iq = 0; iq < ctl->nq; iq++) {
12924 mean[iq][idx] /= np[idx];
12925 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
12926 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
12927 } else
12928 for (int iq = 0; iq < ctl->nq; iq++) {
12929 mean[iq][idx] = NAN;
12930 sigma[iq][idx] = NAN;
12931 }
12932 }
12933
12934 /* Write ASCII data... */
12935 if (ctl->grid_type == 0)
12936 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
12937 t, z, lon, lat, area, dz, np);
12938
12939 /* Write netCDF data... */
12940 else if (ctl->grid_type == 1)
12941 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
12942 t, z, lon, lat, area, dz, np);
12943
12944 /* Error message... */
12945 else
12946 ERRMSG("Grid data format GRID_TYPE unknown!");
12947
12948 /* Free... */
12949 free(cd);
12950 for (int iq = 0; iq < ctl->nq; iq++) {
12951 free(mean[iq]);
12952 free(sigma[iq]);
12953 }
12954 free(vmr_impl);
12955 free(z);
12956 free(lon);
12957 free(lat);
12958 free(area);
12959 free(press);
12960 free(np);
12961 free(ixs);
12962 free(iys);
12963 free(izs);
12964}
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:12968
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:13072
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 12968 of file mptrac.c.

12981 {
12982
12983 FILE *out;
12984
12985 /* Check if gnuplot output is requested... */
12986 if (ctl->grid_gpfile[0] != '-') {
12987
12988 /* Create gnuplot pipe... */
12989 if (!(out = popen("gnuplot", "w")))
12990 ERRMSG("Cannot create pipe to gnuplot!");
12991
12992 /* Set plot filename... */
12993 fprintf(out, "set out \"%s.png\"\n", filename);
12994
12995 /* Set time string... */
12996 double r;
12997 int year, mon, day, hour, min, sec;
12998 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12999 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
13000 year, mon, day, hour, min);
13001
13002 /* Dump gnuplot file to pipe... */
13003 FILE *in;
13004 char line[LEN];
13005 if (!(in = fopen(ctl->grid_gpfile, "r")))
13006 ERRMSG("Cannot open file!");
13007 while (fgets(line, LEN, in))
13008 fprintf(out, "%s", line);
13009 fclose(in);
13010 }
13011
13012 else {
13013
13014 /* Create file... */
13015 if (!(out = fopen(filename, "w")))
13016 ERRMSG("Cannot create file!");
13017 }
13018
13019 /* Write header... */
13020 fprintf(out,
13021 "# $1 = time [s]\n"
13022 "# $2 = altitude [km]\n"
13023 "# $3 = longitude [deg]\n"
13024 "# $4 = latitude [deg]\n"
13025 "# $5 = surface area [km^2]\n"
13026 "# $6 = layer depth [km]\n"
13027 "# $7 = column density (implicit) [kg/m^2]\n"
13028 "# $8 = volume mixing ratio (implicit) [ppv]\n"
13029 "# $9 = number of particles [1]\n");
13030 for (int iq = 0; iq < ctl->nq; iq++)
13031 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
13032 ctl->qnt_unit[iq]);
13033 if (ctl->grid_stddev)
13034 for (int iq = 0; iq < ctl->nq; iq++)
13035 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
13036 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13037 fprintf(out, "\n");
13038
13039 /* Write data... */
13040 for (int ix = 0; ix < ctl->grid_nx; ix++) {
13041 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
13042 fprintf(out, "\n");
13043 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13044 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
13045 fprintf(out, "\n");
13046 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13047 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
13048 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
13049 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
13050 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
13051 for (int iq = 0; iq < ctl->nq; iq++) {
13052 fprintf(out, " ");
13053 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
13054 }
13055 if (ctl->grid_stddev)
13056 for (int iq = 0; iq < ctl->nq; iq++) {
13057 fprintf(out, " ");
13058 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
13059 }
13060 fprintf(out, "\n");
13061 }
13062 }
13063 }
13064 }
13065
13066 /* Close file... */
13067 fclose(out);
13068}
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 13072 of file mptrac.c.

13085 {
13086
13087 char longname[2 * LEN], varname[2 * LEN];
13088
13089 double *help;
13090
13091 int *help2, ncid, dimid[10], varid;
13092
13093 size_t start[2], count[2];
13094
13095 /* Allocate... */
13096 ALLOC(help, double,
13097 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13098 ALLOC(help2, int,
13099 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13100
13101 /* Create file... */
13102 NC(nc_create(filename, NC_NETCDF4, &ncid));
13103
13104 /* Define dimensions... */
13105 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
13106 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
13107 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
13108 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
13109 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
13110
13111 /* Define variables and their attributes... */
13112 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
13113 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
13114 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
13115 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
13116 0);
13117 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
13118 0);
13119 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
13120 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
13121
13122 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
13123 ctl->grid_nc_level, 0);
13124 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
13125 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
13126 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
13127 for (int iq = 0; iq < ctl->nq; iq++) {
13128 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
13129 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
13130 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
13131 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
13132 if (ctl->grid_stddev) {
13133 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
13134 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
13135 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
13136 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
13137 }
13138 }
13139 /* End definitions... */
13140 NC(nc_enddef(ncid));
13141
13142 /* Write data... */
13143 NC_PUT_DOUBLE("time", &t, 0);
13144 NC_PUT_DOUBLE("lon", lon, 0);
13145 NC_PUT_DOUBLE("lat", lat, 0);
13146 NC_PUT_DOUBLE("z", z, 0);
13147 NC_PUT_DOUBLE("area", area, 0);
13148 NC_PUT_DOUBLE("dz", &dz, 0);
13149
13150 for (int ix = 0; ix < ctl->grid_nx; ix++)
13151 for (int iy = 0; iy < ctl->grid_ny; iy++)
13152 for (int iz = 0; iz < ctl->grid_nz; iz++)
13153 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13154 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13155 NC_PUT_DOUBLE("cd", help, 0);
13156
13157 for (int ix = 0; ix < ctl->grid_nx; ix++)
13158 for (int iy = 0; iy < ctl->grid_ny; iy++)
13159 for (int iz = 0; iz < ctl->grid_nz; iz++)
13160 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13161 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13162 NC_PUT_DOUBLE("vmr_impl", help, 0);
13163
13164 for (int ix = 0; ix < ctl->grid_nx; ix++)
13165 for (int iy = 0; iy < ctl->grid_ny; iy++)
13166 for (int iz = 0; iz < ctl->grid_nz; iz++)
13167 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13168 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13169 NC_PUT_INT("np", help2, 0);
13170
13171 for (int iq = 0; iq < ctl->nq; iq++) {
13172 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
13173 for (int ix = 0; ix < ctl->grid_nx; ix++)
13174 for (int iy = 0; iy < ctl->grid_ny; iy++)
13175 for (int iz = 0; iz < ctl->grid_nz; iz++)
13176 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13177 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13178 NC_PUT_DOUBLE(varname, help, 0);
13179 }
13180
13181 if (ctl->grid_stddev)
13182 for (int iq = 0; iq < ctl->nq; iq++) {
13183 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
13184 for (int ix = 0; ix < ctl->grid_nx; ix++)
13185 for (int iy = 0; iy < ctl->grid_ny; iy++)
13186 for (int iz = 0; iz < ctl->grid_nz; iz++)
13187 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13188 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13189 NC_PUT_DOUBLE(varname, help, 0);
13190 }
13191
13192 /* Close file... */
13193 NC(nc_close(ncid));
13194
13195 /* Free... */
13196 free(help);
13197 free(help2);
13198}
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1372

◆ 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 13202 of file mptrac.c.

13205 {
13206
13207 /* Create file... */
13208 FILE *out, *level_log = NULL;
13209 if (!(out = fopen(filename, "w")))
13210 ERRMSG("Cannot create file!");
13211 if (strcmp(ctl->met_comp_logfile, "-") != 0) {
13212 /* Open diagnostics file... */
13213 if (!(level_log = fopen(ctl->met_comp_logfile, "w")))
13214 ERRMSG("Cannot create compression log file!");
13215 compress_log_header(level_log);
13216 LOG(1, "Write compression diagnostics: %s", ctl->met_comp_logfile);
13217 }
13218
13219 /* Write type of binary data... */
13220 FWRITE(&ctl->met_type, int,
13221 1,
13222 out);
13223
13224 /* Write version of binary data... */
13225 int version = 104;
13226 FWRITE(&version, int,
13227 1,
13228 out);
13229
13230 /* Write grid data... */
13231 FWRITE(&met->time, double,
13232 1,
13233 out);
13234 FWRITE(&met->nx, int,
13235 1,
13236 out);
13237 FWRITE(&met->ny, int,
13238 1,
13239 out);
13240 FWRITE(&met->np, int,
13241 1,
13242 out);
13243 FWRITE(met->lon, double,
13244 (size_t) met->nx,
13245 out);
13246 FWRITE(met->lat, double,
13247 (size_t) met->ny,
13248 out);
13249 FWRITE(met->p, double,
13250 (size_t) met->np,
13251 out);
13252
13253 /* Write surface data... */
13254 write_met_bin_2d(out, met, met->ps, "PS");
13255 write_met_bin_2d(out, met, met->ts, "TS");
13256 write_met_bin_2d(out, met, met->zs, "ZS");
13257 write_met_bin_2d(out, met, met->us, "US");
13258 write_met_bin_2d(out, met, met->vs, "VS");
13259 write_met_bin_2d(out, met, met->ess, "ESS");
13260 write_met_bin_2d(out, met, met->nss, "NSS");
13261 write_met_bin_2d(out, met, met->shf, "SHF");
13262 write_met_bin_2d(out, met, met->lsm, "LSM");
13263 write_met_bin_2d(out, met, met->sst, "SST");
13264 write_met_bin_2d(out, met, met->pbl, "PBL");
13265 write_met_bin_2d(out, met, met->pt, "PT");
13266 write_met_bin_2d(out, met, met->tt, "TT");
13267 write_met_bin_2d(out, met, met->zt, "ZT");
13268 write_met_bin_2d(out, met, met->h2ot, "H2OT");
13269 write_met_bin_2d(out, met, met->pct, "PCT");
13270 write_met_bin_2d(out, met, met->pcb, "PCB");
13271 write_met_bin_2d(out, met, met->cl, "CL");
13272 write_met_bin_2d(out, met, met->plcl, "PLCL");
13273 write_met_bin_2d(out, met, met->plfc, "PLFC");
13274 write_met_bin_2d(out, met, met->pel, "PEL");
13275 write_met_bin_2d(out, met, met->cape, "CAPE");
13276 write_met_bin_2d(out, met, met->cin, "CIN");
13277 write_met_bin_2d(out, met, met->o3c, "O3C");
13278
13279 /* Write level data... */
13280 write_met_bin_3d(out, ctl, met, met->z, "Z", 0, level_log);
13281 write_met_bin_3d(out, ctl, met, met->t, "T", 1, level_log);
13282 write_met_bin_3d(out, ctl, met, met->u, "U", 2, level_log);
13283 write_met_bin_3d(out, ctl, met, met->v, "V", 3, level_log);
13284 write_met_bin_3d(out, ctl, met, met->w, "W", 4, level_log);
13285 write_met_bin_3d(out, ctl, met, met->pv, "PV", 5, level_log);
13286 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", 6, level_log);
13287 write_met_bin_3d(out, ctl, met, met->o3, "O3", 7, level_log);
13288 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", 8, level_log);
13289 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", 9, level_log);
13290 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", 10, level_log);
13291 write_met_bin_3d(out, ctl, met, met->swc, "SWC", 11, level_log);
13292 write_met_bin_3d(out, ctl, met, met->cc, "CC", 12, level_log);
13293 if (METVAR != 13)
13294 ERRMSG("Number of meteo variables doesn't match!");
13295
13296 /* Write final flag... */
13297 int final = 999;
13298 FWRITE(&final, int,
13299 1,
13300 out);
13301
13302 /* Close file... */
13303 if (level_log)
13304 fclose(level_log);
13305 fclose(out);
13306}
void compress_log_header(FILE *out)
Write the ASCII header for per-level compression diagnostics.
Definition: mptrac.c:757
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:13339
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:13310
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 13310 of file mptrac.c.

13314 {
13315
13316 float *help;
13317
13318 /* Allocate... */
13319 ALLOC(help, float,
13320 EX * EY);
13321
13322 /* Copy data... */
13323 for (int ix = 0; ix < met->nx; ix++)
13324 for (int iy = 0; iy < met->ny; iy++)
13325 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
13326
13327 /* Write uncompressed data... */
13328 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
13329 FWRITE(help, float,
13330 (size_t) (met->nx * met->ny),
13331 out);
13332
13333 /* Free... */
13334 free(help);
13335}

◆ 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 13339 of file mptrac.c.

13346 {
13347
13348 float *help;
13349
13350 /* Allocate... */
13351 ALLOC(help, float,
13352 EX * EY * EP);
13353
13354 /* Copy data... */
13355#pragma omp parallel for default(shared) collapse(2)
13356 for (int ix = 0; ix < met->nx; ix++)
13357 for (int iy = 0; iy < met->ny; iy++)
13358 for (int ip = 0; ip < met->np; ip++)
13359 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
13360
13361 /* Write uncompressed data... */
13362 if (ctl->met_type == 1) {
13363 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
13364 FWRITE(help, float,
13365 (size_t) (met->nx * met->ny * met->np),
13366 out);
13367 }
13368
13369 /* Write packed data... */
13370 else if (ctl->met_type == 2)
13371 compress_pck(varname, help, (size_t) (met->ny * met->nx),
13372 (size_t) met->np, met->p, 0, ctl->met_pck_zstd,
13373 ctl->met_zstd_level, ctl->met_zstd_nworkers, level_log, out);
13374
13375 /* Write ZFP data... */
13376#ifdef ZFP
13377 else if (ctl->met_type == 3) {
13378 const int precision = ctl->met_zfp_prec[metvar];
13379 const double tolerance = ctl->met_zfp_tol[metvar];
13380 FWRITE(&precision, int,
13381 1,
13382 out);
13383 FWRITE(&tolerance, double,
13384 1,
13385 out);
13386 compress_zfp(varname, help, met->np, met->ny, met->nx, met->p,
13387 precision, tolerance, ctl->met_lossy_scale[metvar], 0,
13388 level_log, out);
13389 }
13390#endif
13391
13392 /* Write zstd data... */
13393#ifdef ZSTD
13394 else if (ctl->met_type == 4)
13395 compress_zstd(varname, help, (size_t) (met->ny * met->nx),
13396 (size_t) met->np, met->p, 0, ctl->met_zstd_level,
13397 ctl->met_zstd_nworkers, level_log, out);
13398#endif
13399
13400 /* Write LZ4 data... */
13401#ifdef LZ4
13402 else if (ctl->met_type == 8)
13403 compress_lz4(varname, help, (size_t) (met->ny * met->nx),
13404 (size_t) met->np, met->p, 0, ctl->met_lz4_accel,
13405 level_log, out);
13406#endif
13407
13408 /* Write cmultiscale data... */
13409#ifdef CMS
13410 else if (ctl->met_type == 5) {
13411 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
13412 (size_t) met->np, met->p, 0, level_log, out);
13413 }
13414#endif
13415
13416 /* Write SZ3 data... */
13417#ifdef SZ3
13418 else if (ctl->met_type == 7) {
13419 const int precision = ctl->met_sz3_prec[metvar];
13420 const double tolerance = ctl->met_sz3_tol[metvar];
13421 FWRITE(&precision, int,
13422 1,
13423 out);
13424 FWRITE(&tolerance, double,
13425 1,
13426 out);
13427 compress_sz3(varname, help, met->np, met->ny, met->nx, met->p,
13428 precision, tolerance, ctl->met_lossy_scale[metvar], 0,
13429 level_log, out);
13430 }
13431#endif
13432
13433 /* Unknown method... */
13434 else {
13435 ERRMSG("MET_TYPE not supported!");
13436
13437 /* This will never execute, hack to avoid compilation error... */
13438 LOG(3, "%d", metvar);
13439 }
13440
13441 /* Free... */
13442 free(help);
13443}
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 13447 of file mptrac.c.

13450 {
13451
13452 /* Create file... */
13453 int ncid, varid;
13454 size_t start[4], count[4];
13455 NC(nc_create(filename, NC_NETCDF4, &ncid));
13456
13457 /* Define dimensions... */
13458 int tid, lonid, latid, levid;
13459 NC(nc_def_dim(ncid, "time", 1, &tid));
13460 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
13461 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
13462 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
13463
13464 /* Define grid... */
13465 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
13466 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
13467 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
13468 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
13469 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
13470
13471 /* Define surface variables... */
13472 int dimid2[2] = { latid, lonid };
13473 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
13474 ctl->met_nc_level, 0);
13475 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
13476 ctl->met_nc_level, 0);
13477 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
13478 ctl->met_nc_level, 0);
13479 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
13480 "m s**-1", ctl->met_nc_level, 0);
13481 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
13482 "m s**-1", ctl->met_nc_level, 0);
13483 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
13484 "Instantaneous eastward turbulent surface stress", "N m**-2",
13485 ctl->met_nc_level, 0);
13486 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
13487 "Instantaneous northward turbulent surface stress", "N m**-2",
13488 ctl->met_nc_level, 0);
13489 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
13490 "Instantaneous surface sensible heat flux", "W m**-1",
13491 ctl->met_nc_level, 0);
13492 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
13493 ctl->met_nc_level, 0);
13494 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
13495 ctl->met_nc_level, 0);
13496 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
13497 ctl->met_nc_level, 0);
13498 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
13499 ctl->met_nc_level, 0);
13500 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
13501 ctl->met_nc_level, 0);
13502 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
13503 ctl->met_nc_level, 0);
13504 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
13505 ctl->met_nc_level, 0);
13506 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
13507 ctl->met_nc_level, 0);
13508 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
13509 ctl->met_nc_level, 0);
13510 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
13511 "kg m**2", ctl->met_nc_level, 0);
13512 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
13513 "Pressure at lifted condensation level (LCL)", "Pa",
13514 ctl->met_nc_level, 0);
13515 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
13516 "Pressure at level of free convection (LFC)", "Pa",
13517 ctl->met_nc_level, 0);
13518 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
13519 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
13520 0);
13521 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
13522 "Convective available potential energy", "J kg**-1",
13523 ctl->met_nc_level, 0);
13524 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
13525 "J kg**-1", ctl->met_nc_level, 0);
13526 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
13527 ctl->met_nc_level, 0);
13528
13529 /* Define level data... */
13530 int dimid3[3] = { levid, latid, lonid };
13531 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
13532 ctl->met_nc_level, ctl->met_nc_quant);
13533 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
13534 ctl->met_nc_level, ctl->met_nc_quant);
13535 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
13536 ctl->met_nc_level, ctl->met_nc_quant);
13537 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
13538 ctl->met_nc_level, ctl->met_nc_quant);
13539 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
13540 ctl->met_nc_level, ctl->met_nc_quant);
13541 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
13542 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
13543 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
13544 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
13545 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
13546 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
13547 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
13548 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
13549 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
13550 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
13551 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
13552 ctl->met_nc_level, ctl->met_nc_quant);
13553
13554 /* End definitions... */
13555 NC(nc_enddef(ncid));
13556
13557 /* Write grid data... */
13558 NC_PUT_DOUBLE("time", &met->time, 0);
13559 NC_PUT_DOUBLE("lon", met->lon, 0);
13560 NC_PUT_DOUBLE("lat", met->lat, 0);
13561 double phelp[EP];
13562 for (int ip = 0; ip < met->np; ip++)
13563 phelp[ip] = 100. * met->p[ip];
13564 NC_PUT_DOUBLE("lev", phelp, 0);
13565
13566 /* Write surface data... */
13567 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
13568 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
13569 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
13570 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
13571 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
13572 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
13573 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
13574 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
13575 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
13576 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
13577 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
13578 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
13579 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
13580 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
13581 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
13582 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
13583 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
13584 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
13585 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
13586 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
13587 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
13588 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
13589 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
13590 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
13591
13592 /* Write level data... */
13593 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
13594 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
13595 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
13596 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
13597 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
13598 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
13599 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
13600 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
13601 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
13602 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
13603 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
13604
13605 /* Close file... */
13606 NC(nc_close(ncid));
13607}
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:13611
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:13641
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2568
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2565
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 13611 of file mptrac.c.

13616 {
13617
13618 int varid;
13619 size_t start[4], count[4];
13620
13621 /* Allocate... */
13622 float *help;
13623 ALLOC(help, float,
13624 EX * EY);
13625
13626 /* Copy data... */
13627 for (int ix = 0; ix < met->nx; ix++)
13628 for (int iy = 0; iy < met->ny; iy++)
13629 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
13630
13631 /* Write data... */
13632 LOG(2, "Write 2-D variable: %s (netCDF)", varname);
13633 NC_PUT_FLOAT(varname, help, 0);
13634
13635 /* Free... */
13636 free(help);
13637}
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1349

◆ 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 13641 of file mptrac.c.

13646 {
13647
13648 int varid;
13649 size_t start[4], count[4];
13650
13651 /* Allocate... */
13652 float *help;
13653 ALLOC(help, float,
13654 EX * EY * EP);
13655
13656 /* Copy data... */
13657 for (int ix = 0; ix < met->nx; ix++)
13658 for (int iy = 0; iy < met->ny; iy++)
13659 for (int ip = 0; ip < met->np; ip++)
13660 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
13661
13662 /* Write data... */
13663 LOG(2, "Write 3-D variable: %s (netCDF)", varname);
13664 NC_PUT_FLOAT(varname, help, 0);
13665
13666 /* Free... */
13667 free(help);
13668}

◆ 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 13672 of file mptrac.c.

13678 {
13679
13680 static FILE *out;
13681
13682 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
13683 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
13684
13685 static int nobs, *obscount, ip, okay;
13686
13687 /* Set timer... */
13688 SELECT_TIMER("WRITE_PROF", "OUTPUT");
13689
13690 /* Init... */
13691 if (t == ctl->t_start) {
13692
13693 /* Check quantity index for mass... */
13694 if (ctl->qnt_m < 0)
13695 ERRMSG("Need quantity mass!");
13696
13697 /* Check molar mass... */
13698 if (ctl->molmass <= 0)
13699 ERRMSG("Specify molar mass!");
13700
13701 /* Allocate... */
13702 ALLOC(lon, double,
13703 ctl->prof_nx);
13704 ALLOC(lat, double,
13705 ctl->prof_ny);
13706 ALLOC(area, double,
13707 ctl->prof_ny);
13708 ALLOC(z, double,
13709 ctl->prof_nz);
13710 ALLOC(press, double,
13711 ctl->prof_nz);
13712 ALLOC(rt, double,
13713 NOBS);
13714 ALLOC(rz, double,
13715 NOBS);
13716 ALLOC(rlon, double,
13717 NOBS);
13718 ALLOC(rlat, double,
13719 NOBS);
13720 ALLOC(robs, double,
13721 NOBS);
13722
13723 /* Read observation data... */
13724 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13725
13726 /* Create new output file... */
13727 LOG(1, "Write profile data: %s", filename);
13728 if (!(out = fopen(filename, "w")))
13729 ERRMSG("Cannot create file!");
13730
13731 /* Write header... */
13732 fprintf(out,
13733 "# $1 = time [s]\n"
13734 "# $2 = altitude [km]\n"
13735 "# $3 = longitude [deg]\n"
13736 "# $4 = latitude [deg]\n"
13737 "# $5 = pressure [hPa]\n"
13738 "# $6 = temperature [K]\n"
13739 "# $7 = volume mixing ratio [ppv]\n"
13740 "# $8 = H2O volume mixing ratio [ppv]\n"
13741 "# $9 = O3 volume mixing ratio [ppv]\n"
13742 "# $10 = observed BT index [K]\n"
13743 "# $11 = number of observations\n");
13744
13745 /* Set grid box size... */
13746 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
13747 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
13748 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
13749
13750 /* Set vertical coordinates... */
13751 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13752 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
13753 press[iz] = P(z[iz]);
13754 }
13755
13756 /* Set horizontal coordinates... */
13757 for (int ix = 0; ix < ctl->prof_nx; ix++)
13758 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
13759 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13760 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
13761 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13762 }
13763 }
13764
13765 /* Set time interval... */
13766 const double t0 = t - 0.5 * ctl->dt_mod;
13767 const double t1 = t + 0.5 * ctl->dt_mod;
13768
13769 /* Allocate... */
13770 ALLOC(mass, double,
13771 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
13772 ALLOC(obsmean, double,
13773 ctl->prof_nx * ctl->prof_ny);
13774 ALLOC(obscount, int,
13775 ctl->prof_nx * ctl->prof_ny);
13776
13777 /* Loop over observations... */
13778 for (int i = 0; i < nobs; i++) {
13779
13780 /* Check time... */
13781 if (rt[i] < t0)
13782 continue;
13783 else if (rt[i] >= t1)
13784 break;
13785
13786 /* Check observation data... */
13787 if (!isfinite(robs[i]))
13788 continue;
13789
13790 /* Calculate indices... */
13791 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
13792 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
13793
13794 /* Check indices... */
13795 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
13796 continue;
13797
13798 /* Get mean observation index... */
13799 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
13800 obsmean[idx] += robs[i];
13801 obscount[idx]++;
13802 }
13803
13804 /* Analyze model data... */
13805 for (ip = 0; ip < atm->np; ip++) {
13806
13807 /* Check time... */
13808 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13809 continue;
13810
13811 /* Get indices... */
13812 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
13813 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
13814 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
13815
13816 /* Check indices... */
13817 if (ix < 0 || ix >= ctl->prof_nx ||
13818 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
13819 continue;
13820
13821 /* Get total mass in grid cell... */
13822 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13823 mass[idx] += atm->q[ctl->qnt_m][ip];
13824 }
13825
13826 /* Extract profiles... */
13827 for (int ix = 0; ix < ctl->prof_nx; ix++)
13828 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13829 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
13830 if (obscount[idx2] > 0) {
13831
13832 /* Check profile... */
13833 okay = 0;
13834 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13835 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13836 if (mass[idx3] > 0) {
13837 okay = 1;
13838 break;
13839 }
13840 }
13841 if (!okay)
13842 continue;
13843
13844 /* Write output... */
13845 fprintf(out, "\n");
13846
13847 /* Loop over altitudes... */
13848 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13849
13850 /* Get temperature, water vapor, and ozone... */
13852 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
13853 lon[ix], lat[iy], &temp, ci, cw, 1);
13854 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
13855 lon[ix], lat[iy], &h2o, ci, cw, 0);
13856 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
13857 lon[ix], lat[iy], &o3, ci, cw, 0);
13858
13859 /* Calculate volume mixing ratio... */
13860 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13861 vmr = MA / ctl->molmass * mass[idx3]
13862 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
13863
13864 /* Write output... */
13865 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
13866 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
13867 obsmean[idx2] / obscount[idx2], obscount[idx2]);
13868 }
13869 }
13870 }
13871
13872 /* Free... */
13873 free(mass);
13874 free(obsmean);
13875 free(obscount);
13876
13877 /* Finalize... */
13878 if (t == ctl->t_stop) {
13879
13880 /* Close output file... */
13881 fclose(out);
13882
13883 /* Free... */
13884 free(lon);
13885 free(lat);
13886 free(area);
13887 free(z);
13888 free(press);
13889 free(rt);
13890 free(rz);
13891 free(rlon);
13892 free(rlat);
13893 free(robs);
13894 }
13895}
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 13899 of file mptrac.c.

13905 {
13906
13907 static FILE *out;
13908
13909 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
13910 kw[EP];
13911
13912 static int nobs, nk;
13913
13914 /* Set timer... */
13915 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT");
13916
13917 /* Init... */
13918 if (t == ctl->t_start) {
13919
13920 /* Allocate... */
13921 ALLOC(rt, double,
13922 NOBS);
13923 ALLOC(rz, double,
13924 NOBS);
13925 ALLOC(rlon, double,
13926 NOBS);
13927 ALLOC(rlat, double,
13928 NOBS);
13929 ALLOC(robs, double,
13930 NOBS);
13931
13932 /* Read observation data... */
13933 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13934
13935 /* Read kernel data... */
13936 if (ctl->sample_kernel[0] != '-')
13937 read_kernel(ctl->sample_kernel, kz, kw, &nk);
13938
13939 /* Create output file... */
13940 LOG(1, "Write sample data: %s", filename);
13941 if (!(out = fopen(filename, "w")))
13942 ERRMSG("Cannot create file!");
13943
13944 /* Write header... */
13945 fprintf(out,
13946 "# $1 = time [s]\n"
13947 "# $2 = altitude [km]\n"
13948 "# $3 = longitude [deg]\n"
13949 "# $4 = latitude [deg]\n"
13950 "# $5 = surface area [km^2]\n"
13951 "# $6 = layer depth [km]\n"
13952 "# $7 = number of particles [1]\n"
13953 "# $8 = column density [kg/m^2]\n"
13954 "# $9 = volume mixing ratio [ppv]\n"
13955 "# $10 = observed BT index [K]\n\n");
13956
13957 /* Set latitude range, squared radius, and area... */
13958 dlat = DY2DEG(ctl->sample_dx);
13959 rmax2 = SQR(ctl->sample_dx);
13960 area = M_PI * rmax2;
13961 }
13962
13963 /* Set time interval for output... */
13964 const double t0 = t - 0.5 * ctl->dt_mod;
13965 const double t1 = t + 0.5 * ctl->dt_mod;
13966
13967 /* Loop over observations... */
13968 for (int i = 0; i < nobs; i++) {
13969
13970 /* Check time... */
13971 if (rt[i] < t0)
13972 continue;
13973 else if (rt[i] >= t1)
13974 break;
13975
13976 /* Calculate Cartesian coordinates... */
13977 double x0[3];
13978 geo2cart(0, rlon[i], rlat[i], x0);
13979
13980 /* Set pressure range... */
13981 const double rp = P(rz[i]);
13982 const double ptop = P(rz[i] + ctl->sample_dz);
13983 const double pbot = P(rz[i] - ctl->sample_dz);
13984
13985 /* Init... */
13986 double mass = 0;
13987 int np = 0;
13988
13989 /* Loop over air parcels... */
13990 //#pragma omp parallel for default(shared) reduction(+:mass,np)
13991 for (int ip = 0; ip < atm->np; ip++) {
13992
13993 /* Check time... */
13994 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13995 continue;
13996
13997 /* Check latitude... */
13998 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
13999 continue;
14000
14001 /* Check horizontal distance... */
14002 double x1[3];
14003 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
14004 if (DIST2(x0, x1) > rmax2)
14005 continue;
14006
14007 /* Check pressure... */
14008 if (ctl->sample_dz > 0)
14009 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
14010 continue;
14011
14012 /* Add mass... */
14013 if (ctl->qnt_m >= 0)
14014 mass +=
14015 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
14016 np++;
14017 }
14018
14019 /* Calculate column density... */
14020 const double cd = mass / (1e6 * area);
14021
14022 /* Calculate volume mixing ratio... */
14023 double vmr = 0;
14024 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
14025 if (mass > 0) {
14026
14027 /* Get temperature... */
14028 double temp;
14030 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
14031 rlon[i], rlat[i], &temp, ci, cw, 1);
14032
14033 /* Calculate volume mixing ratio... */
14034 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
14035 }
14036 } else
14037 vmr = NAN;
14038
14039 /* Write output... */
14040 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
14041 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
14042 }
14043
14044 /* Finalize...... */
14045 if (t == ctl->t_stop) {
14046
14047 /* Close output file... */
14048 fclose(out);
14049
14050 /* Free... */
14051 free(rt);
14052 free(rz);
14053 free(rlon);
14054 free(rlat);
14055 free(robs);
14056 }
14057}
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 14061 of file mptrac.c.

14065 {
14066
14067 static FILE *out;
14068
14069 static double rmax2, x0[3], x1[3];
14070
14071 /* Set timer... */
14072 SELECT_TIMER("WRITE_STATION", "OUTPUT");
14073
14074 /* Init... */
14075 if (t == ctl->t_start) {
14076
14077 /* Write info... */
14078 LOG(1, "Write station data: %s", filename);
14079
14080 /* Create new file... */
14081 if (!(out = fopen(filename, "w")))
14082 ERRMSG("Cannot create file!");
14083
14084 /* Write header... */
14085 fprintf(out,
14086 "# $1 = time [s]\n"
14087 "# $2 = altitude [km]\n"
14088 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
14089 for (int iq = 0; iq < ctl->nq; iq++)
14090 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
14091 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
14092 fprintf(out, "\n");
14093
14094 /* Set geolocation and search radius... */
14095 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
14096 rmax2 = SQR(ctl->stat_r);
14097 }
14098
14099 /* Set time interval for output... */
14100 const double t0 = t - 0.5 * ctl->dt_mod;
14101 const double t1 = t + 0.5 * ctl->dt_mod;
14102
14103 /* Loop over air parcels... */
14104 for (int ip = 0; ip < atm->np; ip++) {
14105
14106 /* Check time... */
14107 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14108 continue;
14109
14110 /* Check time range for station output... */
14111 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
14112 continue;
14113
14114 /* Check station flag... */
14115 if (ctl->qnt_stat >= 0)
14116 if ((int) atm->q[ctl->qnt_stat][ip])
14117 continue;
14118
14119 /* Get Cartesian coordinates... */
14120 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
14121
14122 /* Check horizontal distance... */
14123 if (DIST2(x0, x1) > rmax2)
14124 continue;
14125
14126 /* Set station flag... */
14127 if (ctl->qnt_stat >= 0)
14128 atm->q[ctl->qnt_stat][ip] = 1;
14129
14130 /* Write data... */
14131 fprintf(out, "%.2f %g %g %g",
14132 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
14133 for (int iq = 0; iq < ctl->nq; iq++) {
14134 fprintf(out, " ");
14135 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
14136 }
14137 fprintf(out, "\n");
14138 }
14139
14140 /* Close file... */
14141 if (t == ctl->t_stop)
14142 fclose(out);
14143}
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 14147 of file mptrac.c.

14151 {
14152
14153 FILE *out;
14154
14155 /* Set timer... */
14156 SELECT_TIMER("WRITE_VTK", "OUTPUT");
14157
14158 /* Write info... */
14159 LOG(1, "Write VTK data: %s", filename);
14160
14161 /* Set time interval for output... */
14162 const double t0 = t - 0.5 * ctl->dt_mod;
14163 const double t1 = t + 0.5 * ctl->dt_mod;
14164
14165 /* Create file... */
14166 if (!(out = fopen(filename, "w")))
14167 ERRMSG("Cannot create file!");
14168
14169 /* Count data points... */
14170 int np = 0;
14171 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14172 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14173 continue;
14174 np++;
14175 }
14176
14177 /* Write header... */
14178 fprintf(out,
14179 "# vtk DataFile Version 3.0\n"
14180 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
14181
14182 /* Write point coordinates... */
14183 fprintf(out, "POINTS %d float\n", np);
14184 if (ctl->vtk_sphere) {
14185 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14186 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14187 continue;
14188 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
14189 + ctl->vtk_offset) / RE;
14190 const double coslat = cos(DEG2RAD(atm->lat[ip]));
14191 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
14192 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
14193 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
14194 fprintf(out, "%g %g %g\n", x, y, z);
14195 }
14196 } else
14197 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14198 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14199 continue;
14200 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
14201 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
14202 }
14203
14204 /* Write point data... */
14205 fprintf(out, "POINT_DATA %d\n", np);
14206 for (int iq = 0; iq < ctl->nq; iq++) {
14207 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
14208 ctl->qnt_name[iq]);
14209 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14210 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14211 continue;
14212 fprintf(out, "%g\n", atm->q[iq][ip]);
14213 }
14214 }
14215
14216 /* Close file... */
14217 fclose(out);
14218}