MPTRAC
Functions
mptrac.c File Reference

MPTRAC library definitions. More...

#include "mptrac.h"

Go to the source code of this file.

Functions

void cart2geo (const double *x, double *z, double *lon, double *lat)
 State variables of cuRAND random number generator. More...
 
double clim_oh (const ctl_t *ctl, const clim_t *clim, const double t, const double lon, const double lat, const double p)
 Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal correction based on solar zenith angle. More...
 
void clim_oh_diurnal_correction (const ctl_t *ctl, clim_t *clim)
 Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data. More...
 
double clim_photo (const double rate[CP][CSZA][CO3], const clim_photo_t *photo, const double p, const double sza, const double o3c)
 Calculates the photolysis rate for a given set of atmospheric conditions. More...
 
double clim_tropo (const clim_t *clim, const double t, const double lat)
 Calculates the tropopause pressure based on climatological data. More...
 
void clim_tropo_init (clim_t *clim)
 Initializes the tropopause data in the climatology structure. More...
 
double clim_ts (const clim_ts_t *ts, const double t)
 Interpolates a time series of climatological variables. More...
 
double clim_zm (const clim_zm_t *zm, const double t, const double lat, const double p)
 Interpolates monthly mean zonal mean climatological variables. More...
 
void compress_pck (const char *varname, float *array, const size_t nxy, const size_t nz, const int decompress, 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 precision, const double tolerance)
 Writes a 3-dimensional meteorological variable to a binary file. More...
 
void write_met_nc (const char *filename, const ctl_t *ctl, met_t *met)
 Writes meteorological data to a NetCDF file. More...
 
void write_met_nc_2d (const int ncid, const char *varname, met_t *met, float var[EX][EY], const float scl)
 Writes a 2D meteorological variable to a NetCDF file. More...
 
void write_met_nc_3d (const int ncid, const char *varname, met_t *met, float var[EX][EY][EP], const float scl)
 Writes a 3D meteorological variable to a NetCDF file. More...
 
void write_prof (const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
 Writes profile data to a specified file. More...
 
void write_sample (const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
 Writes sample data to a specified file. More...
 
void write_station (const char *filename, const ctl_t *ctl, atm_t *atm, const double t)
 Writes station data to a specified file. More...
 
void write_vtk (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes VTK (Visualization Toolkit) data to a specified file. More...
 

Detailed Description

MPTRAC library definitions.

Definition in file mptrac.c.

Function Documentation

◆ cart2geo()

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

State variables of cuRAND random number generator.

Converts Cartesian coordinates to geographic coordinates.

Definition at line 74 of file mptrac.c.

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

◆ clim_oh()

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

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

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

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

Definition at line 89 of file mptrac.c.

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

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

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

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

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

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

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

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

◆ compress_pck()

void compress_pck ( const char *  varname,
float *  array,
const size_t  nxy,
const size_t  nz,
const int  decompress,
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.
decompressIf non-zero, the function will decompress the data; otherwise, it will compress the data.
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.
    • 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 680 of file mptrac.c.

686 {
687
688 double min[EP], max[EP], off[EP], scl[EP];
689
690 unsigned short *sarray;
691
692 /* Allocate... */
693 ALLOC(sarray, unsigned short,
694 nxy * nz);
695
696 /* Read compressed stream and decompress array... */
697 if (decompress) {
698
699 /* Write info... */
700 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
701 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
702
703 /* Read data... */
704 FREAD(&scl, double,
705 nz,
706 inout);
707 FREAD(&off, double,
708 nz,
709 inout);
710 FREAD(sarray, unsigned short,
711 nxy * nz,
712 inout);
713
714 /* Convert to float... */
715#pragma omp parallel for default(shared)
716 for (size_t ixy = 0; ixy < nxy; ixy++)
717 for (size_t iz = 0; iz < nz; iz++)
718 array[ixy * nz + iz]
719 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
720 }
721
722 /* Compress array and output compressed stream... */
723 else {
724
725 /* Write info... */
726 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
727 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
728
729 /* Get range... */
730 for (size_t iz = 0; iz < nz; iz++) {
731 min[iz] = array[iz];
732 max[iz] = array[iz];
733 }
734 for (size_t ixy = 1; ixy < nxy; ixy++)
735 for (size_t iz = 0; iz < nz; iz++) {
736 if (array[ixy * nz + iz] < min[iz])
737 min[iz] = array[ixy * nz + iz];
738 if (array[ixy * nz + iz] > max[iz])
739 max[iz] = array[ixy * nz + iz];
740 }
741
742 /* Get offset and scaling factor... */
743 for (size_t iz = 0; iz < nz; iz++) {
744 scl[iz] = (max[iz] - min[iz]) / 65533.;
745 off[iz] = min[iz];
746 }
747
748 /* Convert to short... */
749#pragma omp parallel for default(shared)
750 for (size_t ixy = 0; ixy < nxy; ixy++)
751 for (size_t iz = 0; iz < nz; iz++)
752 if (scl[iz] != 0)
753 sarray[ixy * nz + iz] = (unsigned short)
754 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
755 else
756 sarray[ixy * nz + iz] = 0;
757
758 /* Write data... */
759 FWRITE(&scl, double,
760 nz,
761 inout);
762 FWRITE(&off, double,
763 nz,
764 inout);
765 FWRITE(sarray, unsigned short,
766 nxy * nz,
767 inout);
768 }
769
770 /* Free... */
771 free(sarray);
772}
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:855
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:835
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:453
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:330

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

1014 {
1015
1016 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
1017 const double D = sec / 86400 - 0.5;
1018
1019 /* Geocentric apparent ecliptic longitude [rad]... */
1020 const double g = DEG2RAD(357.529 + 0.98560028 * D);
1021 const double q = 280.459 + 0.98564736 * D;
1022 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
1023
1024 /* Mean obliquity of the ecliptic [rad]... */
1025 const double e = DEG2RAD(23.439 - 0.00000036 * D);
1026
1027 /* Declination [rad]... */
1028 const double sindec = sin(e) * sin(L);
1029
1030 /* Right ascension [rad]... */
1031 const double ra = atan2(cos(e) * sin(L), cos(L));
1032
1033 /* Greenwich Mean Sidereal Time [h]... */
1034 const double GMST = 18.697374558 + 24.06570982441908 * D;
1035
1036 /* Local Sidereal Time [h]... */
1037 const double LST = GMST + lon / 15;
1038
1039 /* Hour angle [rad]... */
1040 const double h = LST / 12 * M_PI - ra;
1041
1042 /* Convert latitude... */
1043 const double lat_help = DEG2RAD(lat);
1044
1045 /* Return cosine of solar zenith angle... */
1046 return sin(lat_help) * sindec + cos(lat_help) * sqrt(1 -
1047 SQR(sindec)) * cos(h);
1048}
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1733

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

1056 {
1057
1058 const int
1059 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1060 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1061
1062 /* Get day of year... */
1063 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
1064 *doy = d0l[mon - 1] + day - 1;
1065 else
1066 *doy = d0[mon - 1] + day - 1;
1067}

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

1609 {
1610
1611 const int
1612 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1613 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1614
1615 int i;
1616
1617 /* Get month and day... */
1618 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
1619 for (i = 11; i > 0; i--)
1620 if (d0l[i] <= doy)
1621 break;
1622 *mon = i + 1;
1623 *day = doy - d0l[i] + 1;
1624 } else {
1625 for (i = 11; i > 0; i--)
1626 if (d0[i] <= doy)
1627 break;
1628 *mon = i + 1;
1629 *day = doy - d0[i] + 1;
1630 }
1631}

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

1638 {
1639
1640 double data[2 * EX];
1641
1642 /* Check size... */
1643 if (n > EX)
1644 ERRMSG("Too many data points!");
1645
1646 /* Allocate... */
1647 gsl_fft_complex_wavetable *wavetable =
1648 gsl_fft_complex_wavetable_alloc((size_t) n);
1649 gsl_fft_complex_workspace *workspace =
1650 gsl_fft_complex_workspace_alloc((size_t) n);
1651
1652 /* Set data (real, complex)... */
1653 for (int i = 0; i < n; i++) {
1654 data[2 * i] = fcReal[i];
1655 data[2 * i + 1] = fcImag[i];
1656 }
1657
1658 /* Calculate FFT... */
1659 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
1660
1661 /* Copy data... */
1662 for (int i = 0; i < n; i++) {
1663 fcReal[i] = data[2 * i];
1664 fcImag[i] = data[2 * i + 1];
1665 }
1666
1667 /* Free... */
1668 gsl_fft_complex_wavetable_free(wavetable);
1669 gsl_fft_complex_workspace_free(workspace);
1670}
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2102
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:335

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

1678 {
1679
1680 const double radius = z + RE;
1681 const double latrad = DEG2RAD(lat);
1682 const double lonrad = DEG2RAD(lon);
1683 const double coslat = cos(latrad);
1684
1685 x[0] = radius * coslat * cos(lonrad);
1686 x[1] = radius * coslat * sin(lonrad);
1687 x[2] = radius * sin(latrad);
1688}

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

1698 {
1699
1700 char repl[LEN];
1701
1702 double t6, r;
1703
1704 int year, mon, day, hour, min, sec;
1705
1706 /* Round time to fixed intervals... */
1707 if (direct == -1)
1708 t6 = floor(t / dt_met) * dt_met;
1709 else
1710 t6 = ceil(t / dt_met) * dt_met;
1711
1712 /* Decode time... */
1713 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1714
1715 /* Set filename of MPTRAC meteo files... */
1716 if (ctl->met_clams == 0) {
1717 if (ctl->met_type == 0)
1718 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1719 else if (ctl->met_type == 1)
1720 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1721 else if (ctl->met_type == 2)
1722 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1723 else if (ctl->met_type == 3)
1724 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1725 else if (ctl->met_type == 4)
1726 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1727 else if (ctl->met_type == 5)
1728 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1729 else if (ctl->met_type == 7)
1730 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
1731 sprintf(repl, "%d", year);
1732 get_met_replace(filename, "YYYY", repl);
1733 sprintf(repl, "%02d", mon);
1734 get_met_replace(filename, "MM", repl);
1735 sprintf(repl, "%02d", day);
1736 get_met_replace(filename, "DD", repl);
1737 sprintf(repl, "%02d", hour);
1738 get_met_replace(filename, "HH", repl);
1739 }
1740
1741 /* Set filename of CLaMS meteo files... */
1742 else {
1743 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1744 sprintf(repl, "%d", year);
1745 get_met_replace(filename, "YYYY", repl);
1746 sprintf(repl, "%02d", year % 100);
1747 get_met_replace(filename, "YY", repl);
1748 sprintf(repl, "%02d", mon);
1749 get_met_replace(filename, "MM", repl);
1750 sprintf(repl, "%02d", day);
1751 get_met_replace(filename, "DD", repl);
1752 sprintf(repl, "%02d", hour);
1753 get_met_replace(filename, "HH", repl);
1754 }
1755}
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:2294
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:1759
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:345
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2551
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:2548
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 1759 of file mptrac.c.

1762 {
1763
1764 char buffer[LEN];
1765
1766 /* Iterate... */
1767 for (int i = 0; i < 3; i++) {
1768
1769 /* Replace sub-string... */
1770 char *ch;
1771 if (!(ch = strstr(orig, search)))
1772 return;
1773 strncpy(buffer, orig, (size_t) (ch - orig));
1774 buffer[ch - orig] = 0;
1775 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1776 orig[0] = 0;
1777 strcpy(orig, buffer);
1778 }
1779}

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

1798 {
1799
1801
1802 ctl->met_tropo = met_tropo;
1803 read_met_tropo(ctl, clim, met);
1804#pragma omp parallel for default(shared) private(ci,cw)
1805 for (int ix = 0; ix < nx; ix++)
1806 for (int iy = 0; iy < ny; iy++) {
1807 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1808 &pt[iy * nx + ix], ci, cw, 1);
1809 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1810 &ps[iy * nx + ix], ci, cw, 0);
1811 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1812 &zs[iy * nx + ix], ci, cw, 0);
1813 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1814 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1815 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1816 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1817 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1818 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1819 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1820 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1821 }
1822}
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:2083
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:10472
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:2025
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:870
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2687
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3624
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3534
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3540
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3627
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3609
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3567
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3606
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 1826 of file mptrac.c.

1834 {
1835
1836 /* Check longitude... */
1837 *lon2 = FMOD(lon, 360.);
1838 if (*lon2 < lons[0])
1839 *lon2 += 360;
1840 else if (*lon2 > lons[nlon - 1])
1841 *lon2 -= 360;
1842
1843 /* Check latitude... */
1844 *lat2 = lat;
1845 if (lats[0] < lats[nlat - 1])
1846 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
1847 else
1848 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
1849}

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

1867 {
1868
1869 if (init) {
1870
1871 /* Check longitude and latitude... */
1872 double lon2, lat2;
1873 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
1874 &lon2, &lat2);
1875
1876 /* Get horizontal indizes... */
1877 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
1878 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
1879
1880 /* Locate the vertical indizes for each edge of the column... */
1881 int ind[2][4];
1882 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1883 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1884
1885 /* Find minimum and maximum indizes... */
1886 ci[2] = ind[0][0];
1887 int k_max = ind[0][0];
1888 for (int i = 0; i < 2; i++)
1889 for (int j = 0; j < 4; j++) {
1890 if (ci[2] > ind[i][j])
1891 ci[2] = ind[i][j];
1892 if (k_max < ind[i][j])
1893 k_max = ind[i][j];
1894 }
1895
1896 /* Get weighting factors for time, longitude and latitude... */
1897 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1898 cw[0] = (lon2 - met0->lon[ci[0]]) /
1899 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1900 cw[1] = (lat2 - met0->lat[ci[1]]) /
1901 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1902
1903 /* Interpolate in time at the lowest level... */
1904 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1905 - heights0[ci[0]][ci[1]][ci[2]])
1906 + heights0[ci[0]][ci[1]][ci[2]];
1907 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1908 - heights0[ci[0]][ci[1] + 1][ci[2]])
1909 + heights0[ci[0]][ci[1] + 1][ci[2]];
1910 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1911 - heights0[ci[0] + 1][ci[1]][ci[2]])
1912 + heights0[ci[0] + 1][ci[1]][ci[2]];
1913 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1914 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1915 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1916
1917 /* Interpolate in latitude direction... */
1918 double height0 = cw[1] * (height01 - height00) + height00;
1919 double height1 = cw[1] * (height11 - height10) + height10;
1920
1921 /* Interpolate in longitude direction... */
1922 double height_bot = cw[0] * (height1 - height0) + height0;
1923
1924 /* Interpolate in time at the upper level... */
1925 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1926 - heights0[ci[0]][ci[1]][ci[2] + 1])
1927 + heights0[ci[0]][ci[1]][ci[2] + 1];
1928 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1929 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1930 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1931 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1932 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1933 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1934 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1935 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1936 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1937
1938 /* Interpolate in latitude direction... */
1939 height0 = cw[1] * (height01 - height00) + height00;
1940 height1 = cw[1] * (height11 - height10) + height10;
1941
1942 /* Interpolate in longitude direction... */
1943 double height_top = cw[0] * (height1 - height0) + height0;
1944
1945 /* Search at higher levels if height is not in box... */
1946 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1947 ((height_bot <= height) || (height_top > height))
1948 && (height_bot >= height) && (ci[2] < k_max))
1949 ||
1950 ((heights0[0][0][0] < heights0[0][0][1]) &&
1951 ((height_bot >= height) || (height_top < height))
1952 && (height_bot <= height) && (ci[2] < k_max))
1953 ) {
1954
1955 ci[2]++;
1956 height_bot = height_top;
1957
1958 /* Interpolate in time at the next level... */
1959 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1960 - heights0[ci[0]][ci[1]][ci[2] + 1])
1961 + heights0[ci[0]][ci[1]][ci[2] + 1];
1962 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1963 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1964 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1965 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1966 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1967 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1968 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1969 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1970 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1971
1972 /* Interpolate in latitude direction... */
1973 height0 = cw[1] * (height01 - height00) + height00;
1974 height1 = cw[1] * (height11 - height10) + height10;
1975
1976 /* Interpolate in longitude direction... */
1977 height_top = cw[0] * (height1 - height0) + height0;
1978 }
1979
1980 /* Get vertical weighting factors... */
1981 cw[2] = (height - height_bot)
1982 / (height_top - height_bot);
1983 }
1984
1985 /* Calculate the needed array values... */
1986 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1987 - array0[ci[0]][ci[1]][ci[2]])
1988 + array0[ci[0]][ci[1]][ci[2]];
1989 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1990 - array0[ci[0] + 1][ci[1]][ci[2]])
1991 + array0[ci[0] + 1][ci[1]][ci[2]];
1992 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1993 - array0[ci[0]][ci[1] + 1][ci[2]])
1994 + array0[ci[0]][ci[1] + 1][ci[2]];
1995 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1996 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1997 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1998 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1999 - array0[ci[0]][ci[1]][ci[2] + 1])
2000 + array0[ci[0]][ci[1]][ci[2] + 1];
2001 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2002 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2003 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2004 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2005 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2006 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2007 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2008 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2009 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2010
2011 const double array00 = cw[0] * (array100 - array000) + array000;
2012 const double array10 = cw[0] * (array110 - array010) + array010;
2013 const double array01 = cw[0] * (array101 - array001) + array001;
2014 const double array11 = cw[0] * (array111 - array011) + array011;
2015
2016 const double aux0 = cw[1] * (array10 - array00) + array00;
2017 const double aux1 = cw[1] * (array11 - array01) + array01;
2018
2019 /* Interpolate vertically... */
2020 *var = cw[2] * (aux1 - aux0) + aux0;
2021}
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:2607
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:1826
int nx
Number of longitudes.
Definition: mptrac.h:3501
int ny
Number of latitudes.
Definition: mptrac.h:3504
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3513
int npl
Number of model levels.
Definition: mptrac.h:3510
double time
Time [s].
Definition: mptrac.h:3498
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3516
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 2025 of file mptrac.c.

2034 {
2035
2036 /* Initialize interpolation... */
2037 if (init) {
2038
2039 /* Check longitude and latitude... */
2040 double lon2, lat2;
2041 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2042 &lon2, &lat2);
2043
2044 /* Get interpolation indices... */
2045 ci[0] = locate_irr(met->p, met->np, p);
2046 ci[1] = locate_reg(met->lon, met->nx, lon2);
2047 ci[2] = locate_irr(met->lat, met->ny, lat2);
2048
2049 /* Get interpolation weights... */
2050 cw[0] = (met->p[ci[0] + 1] - p)
2051 / (met->p[ci[0] + 1] - met->p[ci[0]]);
2052 cw[1] = (met->lon[ci[1] + 1] - lon2)
2053 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2054 cw[2] = (met->lat[ci[2] + 1] - lat2)
2055 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2056 }
2057
2058 /* Interpolate vertically... */
2059 const double aux00 =
2060 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
2061 + array[ci[1]][ci[2]][ci[0] + 1];
2062 const double aux01 =
2063 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
2064 array[ci[1]][ci[2] + 1][ci[0] + 1])
2065 + array[ci[1]][ci[2] + 1][ci[0] + 1];
2066 const double aux10 =
2067 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
2068 array[ci[1] + 1][ci[2]][ci[0] + 1])
2069 + array[ci[1] + 1][ci[2]][ci[0] + 1];
2070 const double aux11 =
2071 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
2072 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
2073 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
2074
2075 /* Interpolate horizontally... */
2076 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2077 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2078 *var = cw[1] * (aux0 - aux1) + aux1;
2079}
int np
Number of pressure levels.
Definition: mptrac.h:3507
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3519
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 2083 of file mptrac.c.

2091 {
2092
2093 /* Initialize interpolation... */
2094 if (init) {
2095
2096 /* Check longitude and latitude... */
2097 double lon2, lat2;
2098 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2099 &lon2, &lat2);
2100
2101 /* Get interpolation indices... */
2102 ci[1] = locate_reg(met->lon, met->nx, lon2);
2103 ci[2] = locate_irr(met->lat, met->ny, lat2);
2104
2105 /* Get interpolation weights... */
2106 cw[1] = (met->lon[ci[1] + 1] - lon2)
2107 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2108 cw[2] = (met->lat[ci[2] + 1] - lat2)
2109 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2110 }
2111
2112 /* Set variables... */
2113 const double aux00 = array[ci[1]][ci[2]];
2114 const double aux01 = array[ci[1]][ci[2] + 1];
2115 const double aux10 = array[ci[1] + 1][ci[2]];
2116 const double aux11 = array[ci[1] + 1][ci[2] + 1];
2117
2118 /* Interpolate horizontally... */
2119 if (isfinite(aux00) && isfinite(aux01)
2120 && isfinite(aux10) && isfinite(aux11)) {
2121 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2122 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2123 *var = cw[1] * (aux0 - aux1) + aux1;
2124 } else {
2125 if (cw[2] < 0.5) {
2126 if (cw[1] < 0.5)
2127 *var = aux11;
2128 else
2129 *var = aux01;
2130 } else {
2131 if (cw[1] < 0.5)
2132 *var = aux10;
2133 else
2134 *var = aux00;
2135 }
2136 }
2137}
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 2141 of file mptrac.c.

2153 {
2154
2155 double var0, var1;
2156
2157 /* Spatial interpolation... */
2158 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
2159 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
2160
2161 /* Get weighting factor... */
2162 const double wt = (met1->time - ts) / (met1->time - met0->time);
2163
2164 /* Interpolate... */
2165 *var = wt * (var0 - var1) + var1;
2166}
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 2170 of file mptrac.c.

2181 {
2182
2183 double var0, var1;
2184
2185 /* Spatial interpolation... */
2186 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
2187 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
2188
2189 /* Get weighting factor... */
2190 const double wt = (met1->time - ts) / (met1->time - met0->time);
2191
2192 /* Interpolate... */
2193 if (isfinite(var0) && isfinite(var1))
2194 *var = wt * (var0 - var1) + var1;
2195 else if (wt < 0.5)
2196 *var = var1;
2197 else
2198 *var = var0;
2199}
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 2203 of file mptrac.c.

2217 {
2218
2219 double mean = 0;
2220
2221 int n = 0;
2222
2223 /* Check longitude and latitude... */
2224 double lon2, lat2;
2225 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
2226
2227 /* Get indices... */
2228 const int ix = locate_reg(lons, (int) nlon, lon2);
2229 const int iy = locate_irr(lats, (int) nlat, lat2);
2230
2231 /* Calculate standard deviation... */
2232 *sigma = 0;
2233 for (int dx = 0; dx < 2; dx++)
2234 for (int dy = 0; dy < 2; dy++) {
2235 if (isfinite(array0[ix + dx][iy + dy])) {
2236 mean += array0[ix + dx][iy + dy];
2237 *sigma += SQR(array0[ix + dx][iy + dy]);
2238 n++;
2239 }
2240 if (isfinite(array1[ix + dx][iy + dy])) {
2241 mean += array1[ix + dx][iy + dy];
2242 *sigma += SQR(array1[ix + dx][iy + dy]);
2243 n++;
2244 }
2245 }
2246 if (n > 0)
2247 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
2248
2249 /* Linear interpolation... */
2250 if (method == 1 && isfinite(array0[ix][iy])
2251 && isfinite(array0[ix][iy + 1])
2252 && isfinite(array0[ix + 1][iy])
2253 && isfinite(array0[ix + 1][iy + 1])
2254 && isfinite(array1[ix][iy])
2255 && isfinite(array1[ix][iy + 1])
2256 && isfinite(array1[ix + 1][iy])
2257 && isfinite(array1[ix + 1][iy + 1])) {
2258
2259 const double aux00 = LIN(lons[ix], array0[ix][iy],
2260 lons[ix + 1], array0[ix + 1][iy], lon2);
2261 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
2262 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2263 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2264
2265 const double aux10 = LIN(lons[ix], array1[ix][iy],
2266 lons[ix + 1], array1[ix + 1][iy], lon2);
2267 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
2268 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2269 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2270
2271 *var = LIN(time0, aux0, time1, aux1, time);
2272 }
2273
2274 /* Nearest neighbor interpolation... */
2275 else {
2276 const double aux00 = NN(lons[ix], array0[ix][iy],
2277 lons[ix + 1], array0[ix + 1][iy], lon2);
2278 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
2279 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2280 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2281
2282 const double aux10 = NN(lons[ix], array1[ix][iy],
2283 lons[ix + 1], array1[ix + 1][iy], lon2);
2284 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
2285 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2286 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2287
2288 *var = NN(time0, aux0, time1, aux1, time);
2289 }
2290}
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1423
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 2294 of file mptrac.c.

2302 {
2303
2304 struct tm t0, *t1;
2305
2306 t0.tm_year = 100;
2307 t0.tm_mon = 0;
2308 t0.tm_mday = 1;
2309 t0.tm_hour = 0;
2310 t0.tm_min = 0;
2311 t0.tm_sec = 0;
2312
2313 const time_t jsec0 = (time_t) jsec + timegm(&t0);
2314 t1 = gmtime(&jsec0);
2315
2316 *year = t1->tm_year + 1900;
2317 *mon = t1->tm_mon + 1;
2318 *day = t1->tm_mday;
2319 *hour = t1->tm_hour;
2320 *min = t1->tm_min;
2321 *sec = t1->tm_sec;
2322 *remain = jsec - floor(jsec);
2323}

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

2331 {
2332
2333 /* Check number of data points... */
2334 if (nk < 2)
2335 return 1.0;
2336
2337 /* Get altitude... */
2338 const double z = Z(p);
2339
2340 /* Get weighting factor... */
2341 if (z < kz[0])
2342 return kw[0];
2343 else if (z > kz[nk - 1])
2344 return kw[nk - 1];
2345 else {
2346 const int idx = locate_irr(kz, nk, z);
2347 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
2348 }
2349}
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 2353 of file mptrac.c.

2355 {
2356
2357 /*
2358 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
2359 and water vapor volume mixing ratio [1].
2360
2361 Reference: https://en.wikipedia.org/wiki/Lapse_rate
2362 */
2363
2364 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
2365
2366 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
2367}
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:306
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1720
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:271
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:261
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:256
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:251

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

2372 {
2373
2374 if (0 == ctl->met_press_level_def) {
2375
2376 ERRMSG
2377 ("MET_PRESS_LEVEL_DEF=0 is disabled. Use 3 for the extended L137 set.");
2378
2379 } else if (1 == ctl->met_press_level_def) {
2380
2381 ERRMSG
2382 ("MET_PRESS_LEVEL_DEF=1 is disabled. Use 4 for the extended L91 set.");
2383
2384 } else if (2 == ctl->met_press_level_def) {
2385
2386 ERRMSG
2387 ("MET_PRESS_LEVEL_DEF=2 is disabled. Use 5 for the extended L60 set.");
2388
2389 } else if (3 == ctl->met_press_level_def) {
2390
2391 ctl->met_np = 147;
2392
2393 const double press[147] = {
2394 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
2395 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
2396 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
2397 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
2398 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2399 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
2400 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
2401 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
2402 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
2403 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
2404 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
2405 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
2406 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2407 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2408 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2409 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2410 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2411 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2412 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
2413 1031.97,
2414 1035.09, 1038.21, 1041.33, 1044.45
2415 };
2416
2417 for (int ip = 0; ip < ctl->met_np; ip++)
2418 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2419
2420 } else if (4 == ctl->met_press_level_def) {
2421
2422 ctl->met_np = 101;
2423
2424 const double press[101] = {
2425 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2426 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2427 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2428 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2429 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2430 113.6382,
2431 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2432 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2433 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2434 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2435 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2436 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2437 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2438 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
2439 1028.85, 1031.97,
2440 1035.09, 1038.21, 1041.33, 1044.45
2441 };
2442
2443 for (int ip = 0; ip < ctl->met_np; ip++)
2444 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2445
2446 } else if (5 == ctl->met_press_level_def) {
2447
2448 ctl->met_np = 62;
2449
2450 const double press[62] = {
2451 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2452 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2453 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2454 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2455 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2456 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2457 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2458 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
2459 1044.45
2460 };
2461
2462 for (int ip = 0; ip < ctl->met_np; ip++)
2463 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2464
2465 } else if (6 == ctl->met_press_level_def) {
2466
2467 ctl->met_np = 137;
2468
2469 const double press[137] = {
2470 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
2471 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
2472 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
2473 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
2474 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
2475 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2476 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
2477 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
2478 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
2479 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
2480 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
2481 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
2482 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
2483 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
2484 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
2485 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
2486 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
2487 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
2488 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
2489 1030.06, 1037.25, 1044.45
2490 };
2491
2492 for (int ip = 0; ip < ctl->met_np; ip++)
2493 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2494
2495 } else if (7 == ctl->met_press_level_def) {
2496
2497 ctl->met_np = 59;
2498
2499 const double press[59] = {
2500 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2501 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2502 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2503 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2504 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2505 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2506 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2507 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2508 1028.53, 1046.13
2509 };
2510
2511 for (int ip = 0; ip < ctl->met_np; ip++)
2512 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2513
2514 } else {
2515 ERRMSG("Use values between 3 and 7.");
2516 }
2517
2518 if (ctl->met_np > EP)
2519 ERRMSG("Recompile with larger EP to use this pressure level definition!");
2520}
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2653
int met_np
Number of target pressure levels.
Definition: mptrac.h:2647
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2650

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

2527 {
2528
2529 int ilo = 0;
2530 int ihi = n - 1;
2531 int i = (ihi + ilo) >> 1;
2532
2533 if (xx[i] < xx[i + 1])
2534 while (ihi > ilo + 1) {
2535 i = (ihi + ilo) >> 1;
2536 if (xx[i] > x)
2537 ihi = i;
2538 else
2539 ilo = i;
2540 } else
2541 while (ihi > ilo + 1) {
2542 i = (ihi + ilo) >> 1;
2543 if (xx[i] <= x)
2544 ihi = i;
2545 else
2546 ilo = i;
2547 }
2548
2549 return ilo;
2550}

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

2558 {
2559
2560 int ilo = 0;
2561 int ihi = n - 1;
2562 int i = (ihi + ilo) >> 1;
2563
2564 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
2565 return ig;
2566
2567 if (xx[i] < xx[i + 1])
2568 while (ihi > ilo + 1) {
2569 i = (ihi + ilo) >> 1;
2570 if (xx[i] > x)
2571 ihi = i;
2572 else
2573 ilo = i;
2574 } else
2575 while (ihi > ilo + 1) {
2576 i = (ihi + ilo) >> 1;
2577 if (xx[i] <= x)
2578 ihi = i;
2579 else
2580 ilo = i;
2581 }
2582
2583 return ilo;
2584}

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

2591 {
2592
2593 /* Calculate index... */
2594 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2595
2596 /* Check range... */
2597 if (i < 0)
2598 return 0;
2599 else if (i > n - 2)
2600 return n - 2;
2601 else
2602 return i;
2603}

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

2613 {
2614
2615 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2616 np, height_ap, 0);
2617 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2618 np, height_ap, ind[0]);
2619 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2620 np, height_ap, ind[1]);
2621 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2622 np, height_ap, ind[2]);
2623}
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:2554
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 2627 of file mptrac.c.

2632 {
2633
2634 /* Set timer... */
2635 SELECT_TIMER("MODULE_ADVECT", "PHYSICS");
2636
2637 /* Use omega vertical velocity... */
2638 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2639
2640 /* Loop over particles... */
2641 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2642
2643 /* Init... */
2645 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2646 x[3] = { 0, 0, 0 };
2647
2648 /* Loop over integration nodes... */
2649 for (int i = 0; i < ctl->advect; i++) {
2650
2651 /* Set position... */
2652 if (i == 0) {
2653 dts = 0.0;
2654 x[0] = atm->lon[ip];
2655 x[1] = atm->lat[ip];
2656 x[2] = atm->p[ip];
2657 } else {
2658 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2659 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2660 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2661 x[2] = atm->p[ip] + dts * w[i - 1];
2662 }
2663 const double tm = atm->time[ip] + dts;
2664
2665 /* Interpolate meteo data on pressure levels... */
2666 if (ctl->advect_vert_coord == 0) {
2667 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2668 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2669 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2670 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2671 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2672 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2673 }
2674
2675 /* Interpolate meteo data on model levels... */
2676 else {
2677 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
2678 met1, met1->pl, met1->ul,
2679 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2680 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
2681 met1, met1->pl, met1->vl,
2682 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2683 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
2684 met1, met1->pl, met1->wl,
2685 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2686 }
2687
2688 /* Get mean wind... */
2689 double k = 1.0;
2690 if (ctl->advect == 2)
2691 k = (i == 0 ? 0.0 : 1.0);
2692 else if (ctl->advect == 4)
2693 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2694 um += k * u[i];
2695 vm += k * v[i];
2696 wm += k * w[i];
2697 }
2698
2699 /* Set new position... */
2700 atm->time[ip] += cache->dt[ip];
2701 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2702 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2703 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2704 atm->p[ip] += cache->dt[ip] * wm;
2705 }
2706 }
2707
2708 /* Use zeta or eta vertical velocity... */
2709 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
2710
2711 /* Select quantity index depending on coordinate... */
2712 const int qnt = (ctl->advect_vert_coord == 1
2713 ? ctl->qnt_zeta : ctl->qnt_eta);
2714
2715 /* Loop over particles... */
2716 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2717
2718 /* Convert pressure to vertical coordinate (zeta or eta)... */
2720 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
2721 met1, met1->pl, met1->zetal,
2722 atm->time[ip], atm->p[ip],
2723 atm->lon[ip], atm->lat[ip],
2724 &atm->q[qnt][ip], ci, cw, 1);
2725
2726 /* Init... */
2727 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
2728 wdotm = 0, x[3] = { 0, 0, 0 };
2729
2730 /* Loop over integration nodes (Runge–Kutta steps)... */
2731 for (int i = 0; i < ctl->advect; i++) {
2732
2733 /* Set position... */
2734 if (i == 0) {
2735 dts = 0.0;
2736 x[0] = atm->lon[ip];
2737 x[1] = atm->lat[ip];
2738 x[2] = atm->q[qnt][ip];
2739 } else {
2740 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2741 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2742 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2743 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
2744 }
2745
2746 const double tm = atm->time[ip] + dts;
2747
2748 /* Interpolate meteo data... */
2749 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
2750 met1, met1->zetal, met1->ul,
2751 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2752 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
2753 met1, met1->zetal, met1->vl,
2754 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2755 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
2756 met1, met1->zetal, met1->zeta_dotl,
2757 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
2758
2759 /* Compute Runge–Kutta weights... */
2760 double k = 1.0;
2761 if (ctl->advect == 2)
2762 k = (i == 0 ? 0.0 : 1.0);
2763 else if (ctl->advect == 4)
2764 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2765
2766 um += k * u[i];
2767 vm += k * v[i];
2768 wdotm += k * wdot[i];
2769 }
2770
2771 /* Update particle position... */
2772 atm->time[ip] += cache->dt[ip];
2773 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2774 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2775 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2776 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
2777
2778 /* Convert vertical coordinate (zeta or eta) back to pressure... */
2779 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
2780 met1, met1->zetal, met1->pl,
2781 atm->time[ip],
2782 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
2783 &atm->p[ip], ci, cw, 1);
2784 }
2785 }
2786}
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:2141
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:1853
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1450
#define SELECT_TIMER(id, group)
Select and start a timer with specific attributes.
Definition: mptrac.h:2176
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:651
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:669
double time[NP]
Time [s].
Definition: mptrac.h:3247
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3256
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3253
int np
Number of air parcels.
Definition: mptrac.h:3244
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3259
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3250
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3317
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2413
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2722
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2404
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:2726
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3660
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3618
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3654
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3651
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3612
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3648
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3615
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3645
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3657
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 2790 of file mptrac.c.

2795 {
2796
2797 /* Check parameters... */
2798 if (ctl->advect_vert_coord != 1)
2799 return;
2800
2801 /* Set timer... */
2802 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS");
2803
2804 /* Loop over particles... */
2805 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
2806
2807 /* Initialize pressure consistent with zeta... */
2809 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
2810 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2811 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2812 }
2813}
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 2817 of file mptrac.c.

2823 {
2824
2825 /* Set timer... */
2826 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS");
2827
2828 /* Check quantity flags... */
2829 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2830 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2831 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2832 return;
2833
2834 /* Loop over particles... */
2835 PARTICLE_LOOP(0, atm->np, 1,
2836 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2837
2838 /* Check latitude and pressure range... */
2839 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2840 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2841 continue;
2842
2843 /* Check surface layer... */
2844 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2845 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2846
2847 /* Get surface pressure... */
2848 double ps;
2850 INTPOL_2D(ps, 1);
2851
2852 /* Check pressure... */
2853 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2854 continue;
2855
2856 /* Check height... */
2857 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2858 continue;
2859
2860 /* Check zeta range... */
2861 if (ctl->bound_zetas > 0) {
2862 double t;
2863 INTPOL_3D(t, 1);
2864 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2865 continue;
2866 }
2867
2868 /* Check planetary boundary layer... */
2869 if (ctl->bound_pbl) {
2870 double pbl;
2871 INTPOL_2D(pbl, 0);
2872 if (atm->p[ip] < pbl)
2873 continue;
2874 }
2875 }
2876
2877 /* Set mass and volume mixing ratio... */
2878 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2879 atm->q[ctl->qnt_m][ip] =
2880 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2881 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2882 atm->q[ctl->qnt_vmr][ip] =
2883 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2884
2885 /* Set CFC-10 volume mixing ratio... */
2886 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2887 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2888
2889 /* Set CFC-11 volume mixing ratio... */
2890 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2891 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2892
2893 /* Set CFC-12 volume mixing ratio... */
2894 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2895 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2896
2897 /* Set N2O volume mixing ratio... */
2898 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2899 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2900
2901 /* Set SF6 volume mixing ratio... */
2902 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2903 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2904
2905 /* Set age of air... */
2906 if (ctl->qnt_aoa >= 0)
2907 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2908 }
2909}
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:387
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:901
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1989
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:884
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3478
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3484
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3472
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3475
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3481
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2482
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2221
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2491
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2852
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2801
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2476
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2774
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2224
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2789
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2807
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2795
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2780
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2786
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2783
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2485
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2479
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2488
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2798
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2777
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2792
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2843
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2855
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2846
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2849
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2804
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 2913 of file mptrac.c.

2918 {
2919
2920 /* Check quantities... */
2921 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
2922 return;
2923 if (ctl->molmass <= 0)
2924 ERRMSG("Molar mass is not defined!");
2925
2926 /* Set timer... */
2927 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS");
2928
2929 /* Allocate... */
2930 const int ensemble_mode = (ctl->nens > 0);
2931 const int np = atm->np;
2932 const int nz = ctl->chemgrid_nz;
2933 const int nx = ctl->chemgrid_nx;
2934 const int ny = ctl->chemgrid_ny;
2935 const int ngrid = nx * ny * nz;
2936 const int nens = ensemble_mode ? ctl->nens : 1;
2937
2938 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2939 double *restrict const press =
2940 (double *) malloc((size_t) nz * sizeof(double));
2941 double *restrict const mass =
2942 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
2943 double *restrict const area =
2944 (double *) malloc((size_t) ny * sizeof(double));
2945 double *restrict const lon =
2946 (double *) malloc((size_t) nx * sizeof(double));
2947 double *restrict const lat =
2948 (double *) malloc((size_t) ny * sizeof(double));
2949
2950 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2951 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2952 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2953
2954 /* Set grid box size... */
2955 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2956 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2957 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2958
2959 /* Set vertical coordinates... */
2960#ifdef _OPENACC
2961#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])
2962#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2963#pragma acc parallel loop independent gang vector
2964#else
2965#pragma omp parallel for default(shared)
2966#endif
2967 for (int iz = 0; iz < nz; iz++) {
2968 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2969 press[iz] = P(z[iz]);
2970 }
2971
2972 /* Set time interval for output... */
2973 const double t0 = tt - 0.5 * ctl->dt_mod;
2974 const double t1 = tt + 0.5 * ctl->dt_mod;
2975
2976 /* Get indices... */
2977#ifdef _OPENACC
2978#pragma acc parallel loop independent gang vector
2979#else
2980#pragma omp parallel for default(shared)
2981#endif
2982 for (int ip = 0; ip < np; ip++) {
2983 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2984 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2985 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2986 if (atm->time[ip] < t0 || atm->time[ip] > t1
2987 || ixs[ip] < 0 || ixs[ip] >= nx
2988 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2989 izs[ip] = -1;
2990 }
2991
2992 /* Set horizontal coordinates... */
2993#ifdef _OPENACC
2994#pragma acc parallel loop independent gang vector
2995#else
2996#pragma omp parallel for default(shared)
2997#endif
2998 for (int ix = 0; ix < nx; ix++)
2999 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3000
3001#ifdef _OPENACC
3002#pragma acc parallel loop independent gang vector
3003#else
3004#pragma omp parallel for default(shared)
3005#endif
3006 for (int iy = 0; iy < ny; iy++) {
3007 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3008 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3009 }
3010
3011 /* Get mass per grid box... */
3012#ifdef _OPENACC
3013#pragma acc parallel loop independent gang vector
3014#endif
3015 for (int ip = 0; ip < np; ip++) {
3016 if (izs[ip] >= 0) {
3017 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3018 if (ensemble_mode) {
3019 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3020 mass_idx += ens * ngrid;
3021 }
3022#ifdef _OPENACC
3023#pragma acc atomic update
3024#endif
3025 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
3026 }
3027 }
3028
3029 /* Assign grid data to air parcels ... */
3030#ifdef _OPENACC
3031#pragma acc parallel loop independent gang vector
3032#else
3033#pragma omp parallel for default(shared)
3034#endif
3035 for (int ip = 0; ip < np; ip++)
3036 if (izs[ip] >= 0) {
3037
3038 /* Interpolate temperature... */
3039 double temp;
3041 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
3042 press[izs[ip]],
3043 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
3044
3045 /* Set mass... */
3046 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3047 if (ensemble_mode) {
3048 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3049 mass_idx += ens * ngrid;
3050 }
3051
3052 /* Calculate volume mixing ratio... */
3053 const double m = mass[mass_idx];
3054 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
3055 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
3056 }
3057
3058 /* Free... */
3059#ifdef _OPENACC
3060#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
3061#endif
3062 free(mass);
3063 free(lon);
3064 free(lat);
3065 free(area);
3066 free(z);
3067 free(press);
3068 free(ixs);
3069 free(iys);
3070 free(izs);
3071}
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:495
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:286
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1480
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1657
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2813
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2900
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2897
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2915
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2918
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2906
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2909
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2527
int nens
Number of ensembles.
Definition: mptrac.h:3069
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2894
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2903
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2912
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2215
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2446
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 3075 of file mptrac.c.

3081 {
3082
3083 /* Set timer... */
3084 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS");
3085
3086 /* Loop over particles... */
3087 PARTICLE_LOOP(0, atm->np, 0,
3088 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3089
3090 /* Set H2O and O3 using meteo data... */
3092 if (ctl->qnt_Ch2o >= 0) {
3093 double h2o;
3094 INTPOL_3D(h2o, 1);
3095 SET_ATM(qnt_Ch2o, h2o);
3096 }
3097 if (ctl->qnt_Co3 >= 0) {
3098 double o3;
3099 INTPOL_3D(o3, 1);
3100 SET_ATM(qnt_Co3, o3);
3101 }
3102
3103 /* Set radical species... */
3104 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
3105 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3106 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
3107 atm->lat[ip], atm->p[ip]));
3108 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
3109 atm->lat[ip], atm->p[ip]));
3110 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
3111 atm->lat[ip], atm->p[ip]));
3112 }
3113}
double clim_oh(const ctl_t *ctl, const clim_t *clim, const double t, const double lon, const double lat, const double p)
Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal co...
Definition: mptrac.c:89
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1676
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3466
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3469
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3463
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2449
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2452
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 3117 of file mptrac.c.

3122 {
3123
3124 /* Set timer... */
3125 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS");
3126
3127 /* Create random numbers... */
3128 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
3129
3130 /* Loop over particles... */
3131 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3132
3133 /* Interpolate surface pressure... */
3134 double ps;
3136 INTPOL_2D(ps, 1);
3137
3138 /* Initialize pressure range for vertical mixing... */
3139 double pbot = ps, ptop = ps;
3140
3141 /* Mixing in the PBL... */
3142 if (ctl->conv_mix_pbl) {
3143
3144 /* Interpolate PBL... */
3145 double pbl;
3146 INTPOL_2D(pbl, 0);
3147
3148 /* Set pressure range... */
3149 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
3150 }
3151
3152 /* Convective mixing... */
3153 if (ctl->conv_cape >= 0) {
3154
3155 /* Interpolate CAPE, CIN, and equilibrium level... */
3156 double cape, cin, pel;
3157 INTPOL_2D(cape, 0);
3158 INTPOL_2D(cin, 0);
3159 INTPOL_2D(pel, 0);
3160
3161 /* Set pressure range... */
3162 if (isfinite(cape) && cape >= ctl->conv_cape
3163 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
3164 ptop = GSL_MIN(ptop, pel);
3165 }
3166
3167 /* Apply vertical mixing... */
3168 if (ptop != pbot && atm->p[ip] >= ptop) {
3169
3170 /* Get density range... */
3171 double tbot, ttop;
3172 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
3173 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
3174 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
3175 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
3176 const double rhobot = pbot / tbot;
3177 const double rhotop = ptop / ttop;
3178
3179 /* Get new density... */
3180 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
3181
3182 /* Get pressure... */
3183 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
3184 }
3185 }
3186}
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:4357
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3314
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2765
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2762
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2759
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2768
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 3238 of file mptrac.c.

3242 {
3243
3244 /* Set timer... */
3245 SELECT_TIMER("MODULE_DECAY", "PHYSICS");
3246
3247 /* Check quantity flags... */
3248 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3249 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3250
3251 /* Loop over particles... */
3252 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
3253
3254 /* Get weighting factor... */
3255 const double w = tropo_weight(clim, atm, ip);
3256
3257 /* Set lifetime... */
3258 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
3259
3260 /* Calculate exponential decay... */
3261 const double aux = exp(-cache->dt[ip] / tdec);
3262 if (ctl->qnt_m >= 0) {
3263 if (ctl->qnt_mloss_decay >= 0)
3264 atm->q[ctl->qnt_mloss_decay][ip]
3265 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3266 atm->q[ctl->qnt_m][ip] *= aux;
3267 if (ctl->qnt_loss_rate >= 0)
3268 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
3269 }
3270 if (ctl->qnt_vmr >= 0)
3271 atm->q[ctl->qnt_vmr][ip] *= aux;
3272 }
3273}
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:11052
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2380
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2377
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2819
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2816
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 3277 of file mptrac.c.

3282 {
3283
3284 /* Set timer... */
3285 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS");
3286
3287 /* Create random numbers... */
3288 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3289
3290 /* Loop over particles... */
3291 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3292
3293 /* Get indices... */
3294 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
3295 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
3296 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
3297
3298 /* Get standard deviations of local wind data... */
3299 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
3300 for (int i = 0; i < 2; i++)
3301 for (int j = 0; j < 2; j++)
3302 for (int k = 0; k < 2; k++) {
3303 umean += met0->u[ix + i][iy + j][iz + k];
3304 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
3305 vmean += met0->v[ix + i][iy + j][iz + k];
3306 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
3307 wmean += met0->w[ix + i][iy + j][iz + k];
3308 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
3309
3310 umean += met1->u[ix + i][iy + j][iz + k];
3311 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
3312 vmean += met1->v[ix + i][iy + j][iz + k];
3313 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
3314 wmean += met1->w[ix + i][iy + j][iz + k];
3315 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
3316 }
3317 usig = usig / 16.f - SQR(umean / 16.f);
3318 usig = (usig > 0 ? sqrtf(usig) : 0);
3319 vsig = vsig / 16.f - SQR(vmean / 16.f);
3320 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
3321 wsig = wsig / 16.f - SQR(wmean / 16.f);
3322 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
3323
3324 /* Set temporal correlations for mesoscale fluctuations... */
3325 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
3326 const double r2 = sqrt(1 - r * r);
3327
3328 /* Calculate horizontal mesoscale wind fluctuations... */
3329 if (ctl->turb_mesox > 0) {
3330 cache->uvwp[ip][0] =
3331 (float) (r * cache->uvwp[ip][0] +
3332 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
3333 atm->lon[ip] +=
3334 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3335
3336 cache->uvwp[ip][1] =
3337 (float) (r * cache->uvwp[ip][1] +
3338 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
3339 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3340 }
3341
3342 /* Calculate vertical mesoscale wind fluctuations... */
3343 if (ctl->turb_mesoz > 0) {
3344 cache->uvwp[ip][2] =
3345 (float) (r * cache->uvwp[ip][2] +
3346 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
3347 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
3348 }
3349 }
3350}
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3311
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2756
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2537
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2753
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 3354 of file mptrac.c.

3359 {
3360
3361 /* Set timer... */
3362 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS");
3363
3364 /* Create random numbers... */
3365 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3366
3367 /* Loop over particles... */
3368 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3369
3370 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
3371 tau_u = 300., tau_w = 100.;
3372
3373 /* Get surface and PBL pressure... */
3374 double pbl, ps;
3376 INTPOL_2D(ps, 1);
3377 INTPOL_2D(pbl, 0);
3378
3379 /* Boundary layer... */
3380 if (atm->p[ip] >= pbl) {
3381
3382 /* Calculate heights... */
3383 const double p = MIN(atm->p[ip], ps);
3384 const double zs = Z(ps);
3385 const double z = 1e3 * (Z(p) - zs);
3386 const double zi = 1e3 * (Z(pbl) - zs);
3387 const double zratio = z / zi;
3388
3389 /* Calculate friction velocity... */
3390 double ess, nss, h2o, t;
3391 INTPOL_2D(ess, 0);
3392 INTPOL_2D(nss, 0);
3393 INTPOL_3D(t, 1);
3394 INTPOL_3D(h2o, 0);
3395 const double rho = RHO(p, TVIRT(t, h2o));
3396 const double tau = sqrt(SQR(ess) + SQR(nss));
3397 const double ustar = sqrt(tau / rho);
3398
3399 /* Get surface sensible heat flux... */
3400 double shf;
3401 INTPOL_2D(shf, 1);
3402
3403 /* Stable or neutral conditions... */
3404 if (shf <= 0) {
3405
3406 /* Calcalute turbulent velocity variances... */
3407 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
3408 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
3409
3410 /* Calculate derivative dsig_w/dz... */
3411 dsigw_dz = -1.3 * ustar / zi;
3412
3413 /* Calcalute Lagrangian timescales... */
3414 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
3415 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
3416 }
3417
3418 /* Unstable conditions... */
3419 else {
3420
3421 /* Convective velocity... */
3422 const double wstar =
3423 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
3424
3425 /* Calcalute turbulent velocity variances... */
3426 sig_u = 1e-2
3427 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
3428 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
3429 * pow(zratio, 2.0 / 3.0)
3430 + (1.8 - 1.4 * zratio) * SQR(ustar));
3431
3432 /* Calculate derivative dsig_w/dz... */
3433 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
3434 * (0.8 *
3435 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
3436 - 1.8 * pow(zratio, 2.0 / 3.0)));
3437
3438 /* Calculate Lagrangian timescales... */
3439 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
3440 const double eps =
3441 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
3442 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
3443 tau_u = 2 * SQR(sig_u) / (C0 * eps);
3444 tau_w = 2 * SQR(sig_w) / (C0 * eps);
3445 }
3446 }
3447
3448 /* Set minimum values... */
3449 sig_u = MAX(sig_u, 0.25);
3450 sig_w = MAX(sig_w, 0.1);
3451 tau_u = MAX(tau_u, 300.);
3452 tau_w = MAX(tau_w, 100.);
3453
3454 /* Update perturbations... */
3455 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
3456 const double ru2 = sqrt(1.0 - SQR(ru));
3457 cache->uvwp[ip][0]
3458 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
3459 cache->uvwp[ip][1]
3460 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
3461
3462 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
3463 const double rw2 = sqrt(1.0 - SQR(rw));
3464 cache->uvwp[ip][2]
3465 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
3466 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
3467
3468 /* Calculate new air parcel position... */
3469 atm->lon[ip] +=
3470 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3471 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3472 atm->p[ip] +=
3473 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
3474 }
3475}
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1895
#define KARMAN
Karman's constant.
Definition: mptrac.h:276
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1849
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:688
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 3479 of file mptrac.c.

3485 {
3486
3487 /* Set timer... */
3488 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS");
3489
3490 /* Create random numbers... */
3491 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3492
3493 /* Loop over particles... */
3494 PARTICLE_LOOP(0, atm->np, 1,
3495 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3496
3497 /* Get PBL and surface pressure... */
3498 double pbl, ps;
3500 INTPOL_2D(pbl, 1);
3501 INTPOL_2D(ps, 0);
3502
3503 /* Get weighting factors... */
3504 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
3505 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
3506 const double wstrat = 1.0 - wpbl - wtrop;
3507
3508 /* Set diffusivity... */
3509 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
3510 + wstrat * ctl->turb_dx_strat;
3511 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
3512 + wstrat * ctl->turb_dz_strat;
3513
3514 /* Horizontal turbulent diffusion... */
3515 if (dx > 0) {
3516 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
3517 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
3518 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
3519 }
3520
3521 /* Vertical turbulent diffusion... */
3522 if (dz > 0) {
3523 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
3524 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
3525 }
3526 }
3527}
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:6745
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2747
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2741
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2738
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2735
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2750
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2744
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 3531 of file mptrac.c.

3536 {
3537
3538 /* Set timer... */
3539 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS");
3540
3541 /* Check quantity flags... */
3542 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3543 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3544
3545 /* Loop over particles... */
3546 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3547
3548 /* Get surface pressure... */
3549 double ps;
3551 INTPOL_2D(ps, 1);
3552
3553 /* Check whether particle is above the surface layer... */
3554 if (atm->p[ip] < ps - ctl->dry_depo_dp)
3555 continue;
3556
3557 /* Set depth of surface layer... */
3558 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
3559
3560 /* Calculate sedimentation velocity for particles... */
3561 double v_dep;
3562 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
3563
3564 /* Get temperature... */
3565 double t;
3566 INTPOL_3D(t, 1);
3567
3568 /* Set deposition velocity... */
3569 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3570 atm->q[ctl->qnt_rhop][ip]);
3571 }
3572
3573 /* Use explicit sedimentation velocity for gases... */
3574 else
3575 v_dep = ctl->dry_depo_vdep;
3576
3577 /* Calculate loss of mass based on deposition velocity... */
3578 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3579 if (ctl->qnt_m >= 0) {
3580 if (ctl->qnt_mloss_dry >= 0)
3581 atm->q[ctl->qnt_mloss_dry][ip]
3582 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3583 atm->q[ctl->qnt_m][ip] *= aux;
3584 if (ctl->qnt_loss_rate >= 0)
3585 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3586 }
3587 if (ctl->qnt_vmr >= 0)
3588 atm->q[ctl->qnt_vmr][ip] *= aux;
3589 }
3590}
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:10817
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2230
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2227
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2975
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2374
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2978
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 3594 of file mptrac.c.

3600 {
3601
3602 /* Set timer... */
3603 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS");
3604
3605 /* Check quantity flags... */
3606 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3607 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3608
3609 /* Parameter of SO2 correction... */
3610 const double a = 3.12541941e-06;
3611 const double b = -5.72532259e-01;
3612 const double low = pow(1. / a, 1. / b);
3613
3614 /* Loop over particles... */
3615 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3616
3617 /* Check whether particle is inside cloud... */
3618 double lwc, rwc;
3620 INTPOL_3D(lwc, 1);
3621 INTPOL_3D(rwc, 0);
3622 if (!(lwc > 0 || rwc > 0))
3623 continue;
3624
3625 /* Get temperature... */
3626 double t;
3627 INTPOL_3D(t, 0);
3628
3629 /* Get molecular density... */
3630 const double M = MOLEC_DENS(atm->p[ip], t);
3631
3632 /* Reaction rate (Berglen et al., 2004)... */
3633 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3634
3635 /* Henry constant of SO2... */
3636 const double H_SO2 =
3637 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3638 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3639
3640 /* Henry constant of H2O2... */
3641 const double H_h2o2 =
3642 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3643
3644 /* Correction factor for high SO2 concentration
3645 (if qnt_Cx is defined, the correction is switched on)... */
3646 double cor = 1.0;
3647 if (ctl->qnt_Cx >= 0)
3648 cor = atm->q[ctl->qnt_Cx][ip] >
3649 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3650
3651 const double h2o2 = H_h2o2
3652 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3653 * M * cor * 1000. / AVO; /* unit: mol/L */
3654
3655 /* Volume water content in cloud [m^3 m^(-3)]... */
3656 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3657 const double CWC = (lwc + rwc) * rho_air / 1e3;
3658
3659 /* Calculate exponential decay (Rolph et al., 1992)... */
3660 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3661 const double aux = exp(-cache->dt[ip] * rate_coef);
3662 if (ctl->qnt_m >= 0) {
3663 if (ctl->qnt_mloss_h2o2 >= 0)
3664 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3665 atm->q[ctl->qnt_m][ip] *= aux;
3666 if (ctl->qnt_loss_rate >= 0)
3667 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3668 }
3669 if (ctl->qnt_vmr >= 0)
3670 atm->q[ctl->qnt_vmr][ip] *= aux;
3671 }
3672}
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:246
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1190
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:316
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2365
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 3676 of file mptrac.c.

3681 {
3682
3683 double t;
3684
3685 /* Set timer... */
3686 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS");
3687
3688 /* Save pressure... */
3689 if (ctl->isosurf == 1) {
3690 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3691 cache->iso_var[ip] = atm->p[ip];
3692 }
3693 }
3694
3695 /* Save density... */
3696 else if (ctl->isosurf == 2) {
3697 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3699 INTPOL_3D(t, 1);
3700 cache->iso_var[ip] = atm->p[ip] / t;
3701 }
3702 }
3703
3704 /* Save potential temperature... */
3705 else if (ctl->isosurf == 3) {
3706 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3708 INTPOL_3D(t, 1);
3709 cache->iso_var[ip] = THETA(atm->p[ip], t);
3710 }
3711 }
3712
3713 /* Read balloon pressure data... */
3714 else if (ctl->isosurf == 4) {
3715
3716 /* Write info... */
3717 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3718
3719 /* Open file... */
3720 FILE *in;
3721 if (!(in = fopen(ctl->balloon, "r")))
3722 ERRMSG("Cannot open file!");
3723
3724 /* Read pressure time series... */
3725 char line[LEN];
3726 while (fgets(line, LEN, in))
3727 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3728 &(cache->iso_ps[cache->iso_n])) == 2)
3729 if ((++cache->iso_n) > NP)
3730 ERRMSG("Too many data points!");
3731
3732 /* Check number of points... */
3733 if (cache->iso_n < 1)
3734 ERRMSG("Could not read any data!");
3735
3736 /* Close file... */
3737 fclose(in);
3738
3739 /* Update of cache data on device... */
3740 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
3741 }
3742}
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:6414
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1820
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:355
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3305
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3308
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3302
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3299
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2719
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2716
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 3746 of file mptrac.c.

3751 {
3752
3753 /* Set timer... */
3754 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS");
3755
3756 /* Loop over particles... */
3757 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
3758
3759 /* Init... */
3760 double t;
3762
3763 /* Restore pressure... */
3764 if (ctl->isosurf == 1)
3765 atm->p[ip] = cache->iso_var[ip];
3766
3767 /* Restore density... */
3768 else if (ctl->isosurf == 2) {
3769 INTPOL_3D(t, 1);
3770 atm->p[ip] = cache->iso_var[ip] * t;
3771 }
3772
3773 /* Restore potential temperature... */
3774 else if (ctl->isosurf == 3) {
3775 INTPOL_3D(t, 1);
3776 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3777 }
3778
3779 /* Interpolate pressure... */
3780 else if (ctl->isosurf == 4) {
3781 if (atm->time[ip] <= cache->iso_ts[0])
3782 atm->p[ip] = cache->iso_ps[0];
3783 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3784 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3785 else {
3786 const int idx =
3787 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3788 atm->p[ip] =
3789 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
3790 cache->iso_ps[idx + 1], atm->time[ip]);
3791 }
3792 }
3793 }
3794}
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 3852 of file mptrac.c.

3858 {
3859
3860 /* Set timer... */
3861 SELECT_TIMER("MODULE_METEO", "PHYSICS");
3862
3863 /* Check quantity flags... */
3864 if (ctl->qnt_tsts >= 0)
3865 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3866 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3867
3868 /* Loop over particles... */
3869 PARTICLE_LOOP(0, atm->np, 0,
3870 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3871
3872 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
3873 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
3874 o3, lwc, rwc, iwc, swc, cc, z, zt;
3875
3876 /* Interpolate meteo data... */
3878 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3879
3880 /* Set quantities... */
3881 SET_ATM(qnt_ps, ps);
3882 SET_ATM(qnt_ts, ts);
3883 SET_ATM(qnt_zs, zs);
3884 SET_ATM(qnt_us, us);
3885 SET_ATM(qnt_vs, vs);
3886 SET_ATM(qnt_ess, ess);
3887 SET_ATM(qnt_nss, nss);
3888 SET_ATM(qnt_shf, shf);
3889 SET_ATM(qnt_lsm, lsm);
3890 SET_ATM(qnt_sst, sst);
3891 SET_ATM(qnt_pbl, pbl);
3892 SET_ATM(qnt_pt, pt);
3893 SET_ATM(qnt_tt, tt);
3894 SET_ATM(qnt_zt, zt);
3895 SET_ATM(qnt_h2ot, h2ot);
3896 SET_ATM(qnt_zg, z);
3897 SET_ATM(qnt_p, atm->p[ip]);
3898 SET_ATM(qnt_t, t);
3899 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3900 SET_ATM(qnt_u, u);
3901 SET_ATM(qnt_v, v);
3902 SET_ATM(qnt_w, w);
3903 SET_ATM(qnt_h2o, h2o);
3904 SET_ATM(qnt_o3, o3);
3905 SET_ATM(qnt_lwc, lwc);
3906 SET_ATM(qnt_rwc, rwc);
3907 SET_ATM(qnt_iwc, iwc);
3908 SET_ATM(qnt_swc, swc);
3909 SET_ATM(qnt_cc, cc);
3910 SET_ATM(qnt_pct, pct);
3911 SET_ATM(qnt_pcb, pcb);
3912 SET_ATM(qnt_cl, cl);
3913 SET_ATM(qnt_plcl, plcl);
3914 SET_ATM(qnt_plfc, plfc);
3915 SET_ATM(qnt_pel, pel);
3916 SET_ATM(qnt_cape, cape);
3917 SET_ATM(qnt_cin, cin);
3918 SET_ATM(qnt_o3c, o3c);
3919 SET_ATM(qnt_hno3,
3920 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3921 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3922 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3923 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3924 atm->lat[ip], atm->p[ip]));
3925 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3926 atm->lat[ip], atm->p[ip]));
3927 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3928 atm->lat[ip], atm->p[ip]));
3929 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3930 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3931 SET_ATM(qnt_psat, PSAT(t));
3932 SET_ATM(qnt_psice, PSICE(t));
3933 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3934 SET_ATM(qnt_sh, SH(h2o));
3935 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3936 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3937 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3938 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3939 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3940 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
3941 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
3942 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
3943 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3944 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3945 SET_ATM(qnt_pv, pv);
3946 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3947 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3948 SET_ATM(qnt_tnat,
3949 nat_temperature(atm->p[ip], h2o,
3950 clim_zm(&clim->hno3, atm->time[ip],
3951 atm->lat[ip], atm->p[ip])));
3952 SET_ATM(qnt_tsts,
3953 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3954 }
3955}
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:6721
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:2353
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1555
#define H0
Scale height [km].
Definition: mptrac.h:266
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1528
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1796
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1632
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:974
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1602
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1771
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1504
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3457
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2443
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2416
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2437
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2410
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2440
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 3959 of file mptrac.c.

3963 {
3964
3965 /* Set timer... */
3966 SELECT_TIMER("MODULE_MIXING", "PHYSICS");
3967
3968 /* Allocate... */
3969 const int np = atm->np;
3970 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3971 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3972 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3973
3974 /* Set grid box size... */
3975 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3976 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3977 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3978
3979 /* Set time interval... */
3980 const double t0 = t - 0.5 * ctl->dt_mod;
3981 const double t1 = t + 0.5 * ctl->dt_mod;
3982
3983 /* Get indices... */
3984#ifdef _OPENACC
3985#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3986#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3987#pragma acc parallel loop independent gang vector
3988#else
3989#pragma omp parallel for default(shared)
3990#endif
3991 for (int ip = 0; ip < np; ip++) {
3992 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3993 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3994 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3995 if (atm->time[ip] < t0 || atm->time[ip] > t1
3996 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3997 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3998 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3999 izs[ip] = -1;
4000 }
4001
4002 /* Calculate interparcel mixing... */
4003 const int use_ensemble = (ctl->nens > 0);
4004
4005 const int quantities[] = {
4006 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
4007 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
4008 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
4009 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
4010 ctl->qnt_Csf6, ctl->qnt_aoa, ctl->qnt_Arn222, ctl->qnt_Apb210,
4011 ctl->qnt_Abe7, ctl->qnt_Acs137, ctl->qnt_Ai131, ctl->qnt_Axe133
4012 };
4013 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
4014
4015 for (int i = 0; i < n_qnt; i++)
4016 if (quantities[i] >= 0)
4017 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
4018 use_ensemble);
4019
4020 /* Free... */
4021#ifdef _OPENACC
4022#pragma acc exit data delete(ixs,iys,izs)
4023#endif
4024 free(ixs);
4025 free(iys);
4026 free(izs);
4027}
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:4031
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2458
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2876
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2873
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2470
int qnt_Acs137
Quantity array index for radioactive activity of Cs-137.
Definition: mptrac.h:2503
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2870
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2455
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2885
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2461
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2888
int qnt_Ai131
Quantity array index for radioactive activity of I-131.
Definition: mptrac.h:2506
int qnt_Apb210
Quantity array index for radioactive activity of Pb-210.
Definition: mptrac.h:2497
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2464
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2867
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2879
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2891
int qnt_Axe133
Quantity array index for radioactive activity of Xe-133.
Definition: mptrac.h:2509
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2473
int qnt_Abe7
Quantity array index for radioactive activity of Be-7.
Definition: mptrac.h:2500
int qnt_Arn222
Quantity array index for radioactive activity of Rn-222.
Definition: mptrac.h:2494
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2467
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2882
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 4031 of file mptrac.c.

4039 {
4040
4041 const int np = atm->np;
4042 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
4043 const int nens = use_ensemble ? ctl->nens : 1;
4044 const int total_grid = ngrid * nens;
4045
4046 double *restrict const cmean =
4047 (double *) malloc((size_t) total_grid * sizeof(double));
4048 int *restrict const count =
4049 (int *) malloc((size_t) total_grid * sizeof(int));
4050
4051 /* Init... */
4052#ifdef _OPENACC
4053#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
4054#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
4055#pragma acc parallel loop independent gang vector
4056#else
4057#ifdef __NVCOMPILER
4058#pragma novector
4059#endif
4060#pragma omp parallel for
4061#endif
4062 for (int i = 0; i < total_grid; i++) {
4063 count[i] = 0;
4064 cmean[i] = 0.0;
4065 }
4066
4067 /* Loop over particles... */
4068#ifdef _OPENACC
4069#pragma acc parallel loop independent gang vector
4070#endif
4071 for (int ip = 0; ip < np; ip++)
4072 if (izs[ip] >= 0) {
4073 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4074 const int idx =
4075 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4076 ctl->mixing_nz);
4077#ifdef _OPENACC
4078#pragma acc atomic update
4079#endif
4080 cmean[idx] += atm->q[qnt_idx][ip];
4081#ifdef _OPENACC
4082#pragma acc atomic update
4083#endif
4084 count[idx]++;
4085 }
4086
4087 /* Compute means... */
4088#ifdef _OPENACC
4089#pragma acc parallel loop independent gang vector
4090#else
4091#ifdef __NVCOMPILER
4092#pragma novector
4093#endif
4094#pragma omp parallel for
4095#endif
4096 for (int i = 0; i < total_grid; i++)
4097 if (count[i] > 0)
4098 cmean[i] /= count[i];
4099
4100 /* Interparcel mixing... */
4101#ifdef _OPENACC
4102#pragma acc parallel loop independent gang vector
4103#else
4104#pragma omp parallel for
4105#endif
4106 for (int ip = 0; ip < np; ip++) {
4107 if (izs[ip] >= 0) {
4108 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4109
4110 double mixparam = 1.0;
4111 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
4112 const double w = tropo_weight(clim, atm, ip);
4113 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
4114 }
4115
4116 const int idx =
4117 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4118 ctl->mixing_nz);
4119 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
4120 }
4121 }
4122
4123 /* Free... */
4124#ifdef _OPENACC
4125#pragma acc exit data delete(cmean,count)
4126#endif
4127 free(cmean);
4128 free(count);
4129}
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2861
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2864
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 4133 of file mptrac.c.

4139 {
4140
4141 /* Set timer... */
4142 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS");
4143
4144 /* Check quantity flags... */
4145 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4146 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4147
4148 /* Parameter of SO2 correction... */
4149 const double a = 4.71572206e-08;
4150 const double b = -8.28782867e-01;
4151 const double low = pow(1. / a, 1. / b);
4152
4153 /* Loop over particles... */
4154 PARTICLE_LOOP(0, atm->np, 1,
4155 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4156
4157 /* Get temperature... */
4158 double t;
4160 INTPOL_3D(t, 1);
4161
4162 /* Calculate molecular density... */
4163 const double M = MOLEC_DENS(atm->p[ip], t);
4164
4165 /* Use constant reaction rate... */
4166 double k = NAN;
4167 if (ctl->oh_chem_reaction == 1)
4168 k = ctl->oh_chem[0];
4169
4170 /* Calculate bimolecular reaction rate... */
4171 else if (ctl->oh_chem_reaction == 2)
4172 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
4173
4174 /* Calculate termolecular reaction rate... */
4175 if (ctl->oh_chem_reaction == 3) {
4176
4177 /* Calculate rate coefficient for X + OH + M -> XOH + M
4178 (JPL Publication 19-05) ... */
4179 const double k0 =
4180 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
4181 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
4182 const double ki =
4183 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
4184 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
4185 const double c = log10(k0 * M / ki);
4186 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
4187 }
4188
4189 /* Correction factor for high SO2 concentration
4190 (if qnt_Cx is defined, the correction is switched on)... */
4191 double cor = 1;
4192 if (ctl->qnt_Cx >= 0)
4193 cor =
4194 atm->q[ctl->qnt_Cx][ip] >
4195 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
4196
4197 /* Calculate exponential decay... */
4198 const double rate_coef =
4199 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
4200 atm->lat[ip], atm->p[ip]) * M * cor;
4201 const double aux = exp(-cache->dt[ip] * rate_coef);
4202 if (ctl->qnt_m >= 0) {
4203 if (ctl->qnt_mloss_oh >= 0)
4204 atm->q[ctl->qnt_mloss_oh][ip]
4205 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4206 atm->q[ctl->qnt_m][ip] *= aux;
4207 if (ctl->qnt_loss_rate >= 0)
4208 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4209 }
4210 if (ctl->qnt_vmr >= 0)
4211 atm->q[ctl->qnt_vmr][ip] *= aux;
4212 }
4213}
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2924
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2921
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2362
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 4217 of file mptrac.c.

4221 {
4222
4223 /* Set timer... */
4224 SELECT_TIMER("MODULE_POSITION", "PHYSICS");
4225
4226 /* Loop over particles... */
4227 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
4228
4229 /* Init... */
4230 double ps;
4232
4233 /* Calculate modulo... */
4234 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
4235 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
4236
4237 /* Check latitude... */
4238 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
4239 if (atm->lat[ip] > 90) {
4240 atm->lat[ip] = 180 - atm->lat[ip];
4241 atm->lon[ip] += 180;
4242 }
4243 if (atm->lat[ip] < -90) {
4244 atm->lat[ip] = -180 - atm->lat[ip];
4245 atm->lon[ip] += 180;
4246 }
4247 }
4248
4249 /* Check longitude... */
4250 while (atm->lon[ip] < -180)
4251 atm->lon[ip] += 360;
4252 while (atm->lon[ip] >= 180)
4253 atm->lon[ip] -= 360;
4254
4255 /* Check pressure... */
4256 if (atm->p[ip] < met0->p[met0->np - 1]) {
4257 atm->p[ip] = met0->p[met0->np - 1];
4258 } else if (atm->p[ip] > 300.) {
4259 INTPOL_2D(ps, 1);
4260 if (atm->p[ip] > ps)
4261 atm->p[ip] = ps;
4262 }
4263 }
4264}

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

4271 {
4272
4273 /* Set timer... */
4274 SELECT_TIMER("MODULE_RADIO_DECAY", "PHYSICS");
4275
4276 /* Set decay constants of radioactive species [s^-1]... */
4277 const double lambda_rn222 = log(2.0) / (3.8235 * 86400.0);
4278 const double lambda_pb210 = log(2.0) / (22.3 * 365.25 * 86400.0);
4279 const double lambda_be7 = log(2.0) / (53.22 * 86400.0);
4280 const double lambda_cs137 = log(2.0) / (30.05 * 365.25 * 86400.0);
4281 const double lambda_i131 = log(2.0) / (8.02 * 86400.0);
4282 const double lambda_xe133 = log(2.0) / (5.2474 * 86400.0);
4283
4284 /* Loop over particles... */
4285 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,atm)") {
4286
4287 /* Set timestep... */
4288 const double dt = cache->dt[ip];
4289
4290 /* Loss for Pb-210... */
4291 if (ctl->qnt_Apb210 >= 0)
4292 atm->q[ctl->qnt_Apb210][ip] *= exp(-dt * lambda_pb210);
4293
4294 /* Loss for Rn-222... */
4295 if (ctl->qnt_Arn222 >= 0) {
4296 const double old = atm->q[ctl->qnt_Arn222][ip];
4297 const double aux = exp(-dt * lambda_rn222);
4298 const double lost = old * (1.0 - aux);
4299 atm->q[ctl->qnt_Arn222][ip] = old * aux;
4300
4301 /* Parent-daughter process for Pb-210... */
4302 if (ctl->qnt_Apb210 >= 0)
4303 atm->q[ctl->qnt_Apb210][ip] += lost * lambda_pb210 / lambda_rn222;
4304 }
4305
4306 /* Loss for Be-7... */
4307 if (ctl->qnt_Abe7 >= 0)
4308 atm->q[ctl->qnt_Abe7][ip] *= exp(-dt * lambda_be7);
4309
4310 /* Loss for Cs-137... */
4311 if (ctl->qnt_Acs137 >= 0)
4312 atm->q[ctl->qnt_Acs137][ip] *= exp(-dt * lambda_cs137);
4313
4314 /* Loss for I-131... */
4315 if (ctl->qnt_Ai131 >= 0)
4316 atm->q[ctl->qnt_Ai131][ip] *= exp(-dt * lambda_i131);
4317
4318 /* Loss for Xe-133... */
4319 if (ctl->qnt_Axe133 >= 0)
4320 atm->q[ctl->qnt_Axe133][ip] *= exp(-dt * lambda_xe133);
4321 }
4322}

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

4327 {
4328
4329 /* Initialize GSL random number generators... */
4330 gsl_rng_env_setup();
4331 if (omp_get_max_threads() > NTHREADS)
4332 ERRMSG("Too many threads!");
4333 for (int i = 0; i < NTHREADS; i++) {
4334 rng[i] = gsl_rng_alloc(gsl_rng_default);
4335 gsl_rng_set(rng[i], gsl_rng_default_seed
4336 + (long unsigned) (ntask * NTHREADS + i));
4337 }
4338
4339 /* Initialize cuRAND random number generators... */
4340#ifdef CURAND
4341 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
4342 CURAND_STATUS_SUCCESS)
4343 ERRMSG("Cannot create random number generator!");
4344 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
4345 CURAND_STATUS_SUCCESS)
4346 ERRMSG("Cannot set seed for random number generator!");
4347 if (curandSetStream
4348 (rng_curand,
4349 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
4350 CURAND_STATUS_SUCCESS)
4351 ERRMSG("Cannot set stream for random number generator!");
4352#endif
4353}
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:380

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

4361 {
4362
4363 /* Use GSL random number generators... */
4364 if (ctl->rng_type == 0) {
4365
4366 /* Uniform distribution... */
4367 if (method == 0) {
4368#pragma omp parallel for default(shared)
4369 for (size_t i = 0; i < n; ++i)
4370 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
4371 }
4372
4373 /* Normal distribution... */
4374 else if (method == 1) {
4375#pragma omp parallel for default(shared)
4376 for (size_t i = 0; i < n; ++i)
4377 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
4378 }
4379
4380 /* Update of random numbers on device... */
4381#ifdef _OPENACC
4382 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
4383#pragma acc update device(rs[:n])
4384#endif
4385 }
4386
4387 /* Use Squares random number generator (Widynski, 2022)... */
4388 else if (ctl->rng_type == 1) {
4389
4390 /* Set key (don't change this!)... */
4391 const uint64_t key = 0xc8e4fd154ce32f6d;
4392
4393 /* Uniform distribution... */
4394#ifdef _OPENACC
4395#pragma acc data present(rs)
4396#pragma acc parallel loop independent gang vector
4397#else
4398#pragma omp parallel for default(shared)
4399#endif
4400 for (size_t i = 0; i < n + 1; ++i) {
4401 uint64_t r, t, x, y, z;
4402 y = x = (rng_ctr + i) * key;
4403 z = y + key;
4404 x = x * x + y;
4405 x = (x >> 32) | (x << 32);
4406 x = x * x + z;
4407 x = (x >> 32) | (x << 32);
4408 x = x * x + y;
4409 x = (x >> 32) | (x << 32);
4410 t = x = x * x + z;
4411 x = (x >> 32) | (x << 32);
4412 r = t ^ ((x * x + y) >> 32);
4413 rs[i] = (double) r / (double) UINT64_MAX;
4414 }
4415 rng_ctr += n + 1;
4416
4417 /* Normal distribution... */
4418 if (method == 1) {
4419#ifdef _OPENACC
4420#pragma acc parallel loop independent gang vector
4421#else
4422#pragma omp parallel for default(shared)
4423#endif
4424 for (size_t i = 0; i < n; i += 2) {
4425 const double r = sqrt(-2.0 * log(rs[i]));
4426 const double phi = 2.0 * M_PI * rs[i + 1];
4427 rs[i] = r * cosf((float) phi);
4428 rs[i + 1] = r * sinf((float) phi);
4429 }
4430 }
4431 }
4432
4433 /* Use cuRAND random number generators... */
4434 else if (ctl->rng_type == 2) {
4435#ifdef CURAND
4436#pragma acc host_data use_device(rs)
4437 {
4438
4439 /* Uniform distribution... */
4440 if (method == 0) {
4441 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
4442 CURAND_STATUS_SUCCESS)
4443 ERRMSG("Cannot create random numbers!");
4444 }
4445
4446 /* Normal distribution... */
4447 else if (method == 1) {
4448 if (curandGenerateNormalDouble
4449 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
4450 1.0) != CURAND_STATUS_SUCCESS)
4451 ERRMSG("Cannot create random numbers!");
4452 }
4453 }
4454#else
4455 ERRMSG("MPTRAC was compiled without cuRAND!");
4456#endif
4457 }
4458}
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2729

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

4467 {
4468
4469 /* Set timer... */
4470 SELECT_TIMER("MODULE_SEDI", "PHYSICS");
4471
4472 /* Loop over particles... */
4473 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4474
4475 /* Get temperature... */
4476 double t;
4478 INTPOL_3D(t, 1);
4479
4480 /* Sedimentation velocity... */
4481 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4482 atm->q[ctl->qnt_rhop][ip]);
4483
4484 /* Calculate pressure change... */
4485 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
4486 }
4487}
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 4491 of file mptrac.c.

4494 {
4495
4496 /* Set timer... */
4497 SELECT_TIMER("MODULE_SORT", "PHYSICS");
4498
4499 /* Allocate... */
4500 const int np = atm->np;
4501 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
4502 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
4503 if (a == NULL || p == NULL)
4504 ERRMSG("Out of memory!");
4505
4506#ifdef _OPENACC
4507#pragma acc enter data create(a[0:np],p[0:np])
4508#pragma acc data present(ctl,met0,atm,a,p)
4509#endif
4510
4511 /* Get box index... */
4512#ifdef _OPENACC
4513#pragma acc parallel loop independent gang vector
4514#else
4515#pragma omp parallel for default(shared)
4516#endif
4517 for (int ip = 0; ip < np; ip++) {
4518 a[ip] =
4519 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
4520 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
4521 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
4522 p[ip] = ip;
4523 }
4524
4525 /* Sorting... */
4526#ifdef THRUST
4527#ifdef _OPENACC
4528#pragma acc host_data use_device(a,p)
4529#endif
4530 thrustSortWrapper(a, np, p);
4531#else
4532 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
4533 if (perm_sz == NULL)
4534 ERRMSG("Out of memory!");
4535#ifdef _OPENACC
4536#pragma acc update self(a[0:np])
4537#endif
4538 gsl_sort_index(perm_sz, a, 1, (size_t) np);
4539 for (int ip = 0; ip < np; ++ip)
4540 p[ip] = (int) perm_sz[ip];
4541 free(perm_sz);
4542#ifdef _OPENACC
4543#pragma acc update device(p[0:np])
4544#endif
4545#endif
4546
4547 /* Sort data... */
4548 module_sort_help(atm->time, p, np);
4549 module_sort_help(atm->p, p, np);
4550 module_sort_help(atm->lon, p, np);
4551 module_sort_help(atm->lat, p, np);
4552 for (int iq = 0; iq < ctl->nq; iq++)
4553 module_sort_help(atm->q[iq], p, np);
4554
4555 /* Free... */
4556#ifdef _OPENACC
4557#pragma acc exit data delete(a,p)
4558#endif
4559 free(a);
4560 free(p);
4561}
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:4565
int nq
Number of quantities.
Definition: mptrac.h:2197
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 4565 of file mptrac.c.

4568 {
4569
4570 /* Allocate... */
4571 double *restrict const help =
4572 (double *) malloc((size_t) np * sizeof(double));
4573 if (help == NULL)
4574 ERRMSG("Out of memory!");
4575
4576 /* Reordering of array... */
4577#ifdef _OPENACC
4578#pragma acc enter data create(help[0:np])
4579#pragma acc data present(a,p,help)
4580#pragma acc parallel loop independent gang vector
4581#else
4582#pragma omp parallel for default(shared)
4583#endif
4584 for (int ip = 0; ip < np; ip++)
4585 help[ip] = a[p[ip]];
4586#ifdef _OPENACC
4587#pragma acc parallel loop independent gang vector
4588#else
4589#pragma omp parallel for default(shared)
4590#endif
4591 for (int ip = 0; ip < np; ip++)
4592 a[ip] = help[ip];
4593
4594 /* Free... */
4595#ifdef _OPENACC
4596#pragma acc exit data delete(help)
4597#endif
4598 free(help);
4599}

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

4608 {
4609
4610 /* Set timer... */
4611 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS");
4612
4613 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
4614 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
4615
4616 const int local =
4617 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
4618
4619 /* Loop over particles... */
4620 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
4621
4622 /* Set time step for each air parcel... */
4623 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
4624 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
4625 && ctl->direction * (atm->time[ip] - t) < 0))
4626 cache->dt[ip] = t - atm->time[ip];
4627 else
4628 cache->dt[ip] = 0.0;
4629
4630 /* Check horizontal boundaries of local meteo data... */
4631#ifndef DD
4632 int dd = 1;
4633#else
4634 int dd = 0;
4635#endif
4636 if (dd) {
4637 if (local && (atm->lon[ip] <= met0->lon[0]
4638 || atm->lon[ip] >= met0->lon[met0->nx - 1]
4639 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
4640 cache->dt[ip] = 0.0;
4641 } else {
4642 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
4643 cache->dt[ip] = 0;
4644 }
4645 }
4646}
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2518
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2524
int qnt_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2512
double t_start
Start time of simulation [s].
Definition: mptrac.h:2521

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

4652 {
4653
4654 /* Set timer... */
4655 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS");
4656
4657 /* Set start time... */
4658 if (ctl->direction == 1) {
4659 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4660 if (ctl->t_stop > 1e99)
4661 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4662 } else {
4663 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4664 if (ctl->t_stop > 1e99)
4665 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4666 }
4667
4668 /* Check time interval... */
4669 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4670 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4671
4672 /* Round start time... */
4673 if (ctl->direction == 1)
4674 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4675 else
4676 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4677}

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

4687 {
4688
4689 /* Set timer... */
4690 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS");
4691
4692 /* Loop over particles... */
4693 PARTICLE_LOOP(0, atm->np, 1,
4694 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4695
4696 /* Get temperature... */
4697 double t;
4699 INTPOL_3D(t, 1);
4700
4701 /* Get molecular density... */
4702 const double M = MOLEC_DENS(atm->p[ip], t);
4703
4704 /* Get total column ozone... */
4705 double o3c;
4706 INTPOL_2D(o3c, 1);
4707
4708 /* Get solar zenith angle... */
4709 const double sza =
4710 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
4711
4712 /* Get O(1D) volume mixing ratio... */
4713 const double o1d =
4714 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4715
4716 /* Reactions for CFC-10... */
4717 if (ctl->qnt_Cccl4 >= 0) {
4718 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4719 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4720 atm->p[ip], sza, o3c);
4721 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4722 }
4723
4724 /* Reactions for CFC-11... */
4725 if (ctl->qnt_Cccl3f >= 0) {
4726 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4727 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4728 atm->p[ip], sza, o3c);
4729 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4730 }
4731
4732 /* Reactions for CFC-12... */
4733 if (ctl->qnt_Cccl2f2 >= 0) {
4734 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4735 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4736 atm->p[ip], sza, o3c);
4737 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4738 }
4739
4740 /* Reactions for N2O... */
4741 if (ctl->qnt_Cn2o >= 0) {
4742 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4743 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4744 atm->p[ip], sza, o3c);
4745 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4746 }
4747 }
4748}
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:147
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:520
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3358
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3355
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3349
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3352
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3454
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 4752 of file mptrac.c.

4757 {
4758
4759 /* Set timer... */
4760 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS");
4761
4762 /* Check quantity flags... */
4763 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4764 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4765
4766 /* Loop over particles... */
4767 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4768
4769 /* Check whether particle is below cloud top... */
4770 double pct;
4772 INTPOL_2D(pct, 1);
4773 if (!isfinite(pct) || atm->p[ip] <= pct)
4774 continue;
4775
4776 /* Get cloud bottom pressure... */
4777 double pcb;
4778 INTPOL_2D(pcb, 0);
4779
4780 /* Estimate precipitation rate (Pisso et al., 2019)... */
4781 double cl;
4782 INTPOL_2D(cl, 0);
4783 const double Is =
4784 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4785 if (Is < 0.01)
4786 continue;
4787
4788 /* Check whether particle is inside or below cloud... */
4789 double lwc, rwc, iwc, swc;
4790 INTPOL_3D(lwc, 1);
4791 INTPOL_3D(rwc, 0);
4792 INTPOL_3D(iwc, 0);
4793 INTPOL_3D(swc, 0);
4794 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4795
4796 /* Get temperature... */
4797 double t;
4798 INTPOL_3D(t, 0);
4799
4800 /* Calculate in-cloud scavenging coefficient... */
4801 double lambda = 0;
4802 if (inside) {
4803
4804 /* Calculate retention factor... */
4805 double eta;
4806 if (t > 273.15)
4807 eta = 1;
4808 else if (t <= 238.15)
4809 eta = ctl->wet_depo_ic_ret_ratio;
4810 else
4811 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4812
4813 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4814 if (ctl->wet_depo_ic_a > 0)
4815 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4816
4817 /* Use Henry's law for gases... */
4818 else if (ctl->wet_depo_ic_h[0] > 0) {
4819
4820 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4821 double h = ctl->wet_depo_ic_h[0]
4822 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4823
4824 /* Use effective Henry's constant for SO2
4825 (Berglen, 2004; Simpson, 2012)... */
4826 if (ctl->wet_depo_so2_ph > 0) {
4827 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
4828 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4829 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4830 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
4831 }
4832
4833 /* Estimate depth of cloud layer... */
4834 const double dz = 1e3 * (Z(pct) - Z(pcb));
4835
4836 /* Calculate scavenging coefficient... */
4837 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4838 }
4839 }
4840
4841 /* Calculate below-cloud scavenging coefficient... */
4842 else {
4843
4844 /* Calculate retention factor... */
4845 double eta;
4846 if (t > 270)
4847 eta = 1;
4848 else
4849 eta = ctl->wet_depo_bc_ret_ratio;
4850
4851 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4852 if (ctl->wet_depo_bc_a > 0)
4853 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4854
4855 /* Use Henry's law for gases... */
4856 else if (ctl->wet_depo_bc_h[0] > 0) {
4857
4858 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4859 const double h = ctl->wet_depo_bc_h[0]
4860 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4861
4862 /* Estimate depth of cloud layer... */
4863 const double dz = 1e3 * (Z(pct) - Z(pcb));
4864
4865 /* Calculate scavenging coefficient... */
4866 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4867 }
4868 }
4869
4870 /* Calculate exponential decay of mass... */
4871 const double aux = exp(-cache->dt[ip] * lambda);
4872 if (ctl->qnt_m >= 0) {
4873 if (ctl->qnt_mloss_wet >= 0)
4874 atm->q[ctl->qnt_mloss_wet][ip]
4875 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4876 atm->q[ctl->qnt_m][ip] *= aux;
4877 if (ctl->qnt_loss_rate >= 0)
4878 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4879 }
4880 if (ctl->qnt_vmr >= 0)
4881 atm->q[ctl->qnt_vmr][ip] *= aux;
4882 }
4883}
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2954
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2948
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2371
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2966
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2945
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2963
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2972
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2960
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2969
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2957
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2951

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

4894 {
4895
4896 /* Initialize GPU... */
4897#ifdef _OPENACC
4898 SELECT_TIMER("ACC_INIT", "INIT");
4899 int rank = 0;
4900#ifdef MPI
4901 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
4902#endif
4903 if (acc_get_num_devices(acc_device_nvidia) <= 0)
4904 ERRMSG("Not running on a GPU device!");
4905 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
4906 acc_device_nvidia);
4907 acc_device_t device_type = acc_get_device_type();
4908 acc_init(device_type);
4909#endif
4910
4911 /* Allocate... */
4912 SELECT_TIMER("ALLOC", "MEMORY");
4913 ALLOC(*ctl, ctl_t, 1);
4914 ALLOC(*cache, cache_t, 1);
4915 ALLOC(*clim, clim_t, 1);
4916 ALLOC(*met0, met_t, 1);
4917 ALLOC(*met1, met_t, 1);
4918 ALLOC(*atm, atm_t, 1);
4919 ALLOC(*dd, dd_t, 1);
4920
4921 /* Create data region on GPU... */
4922#ifdef _OPENACC
4923 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY");
4924 ctl_t *ctlup = *ctl;
4925 cache_t *cacheup = *cache;
4926 clim_t *climup = *clim;
4927 met_t *met0up = *met0;
4928 met_t *met1up = *met1;
4929 atm_t *atmup = *atm;
4930#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
4931#ifdef DD
4932 dd_t *ddup = *dd;
4933#pragma acc enter data create(ddup[:1])
4934#endif
4935#endif
4936}
Air parcel data.
Definition: mptrac.h:3241
Cache data structure.
Definition: mptrac.h:3296
Climatological data.
Definition: mptrac.h:3436
Control parameters.
Definition: mptrac.h:2190
Domain decomposition data structure.
Definition: mptrac.h:3669
Meteo data structure.
Definition: mptrac.h:3495

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

4947 {
4948
4949 /* Delete data region on GPU... */
4950#ifdef _OPENACC
4951 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY");
4952#pragma acc exit data delete(ctl,cache,clim,met0,met1,atm)
4953#ifdef DD
4954#pragma acc exit data delete(dd)
4955#endif
4956#endif
4957
4958 /* Free... */
4959 SELECT_TIMER("FREE", "MEMORY");
4960 free(atm);
4961 free(ctl);
4962 free(cache);
4963 free(clim);
4964 free(met0);
4965 free(met1);
4966
4967 /* Free MPI datatype... */
4968#ifdef DD
4969 MPI_Type_free(&dd->MPI_Particle);
4970#endif
4971 free(dd);
4972}

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

4982 {
4983
4984 static int init;
4985
4986 met_t *mets;
4987
4988 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
4989
4990 /* Set timer... */
4991 SELECT_TIMER("GET_MET", "INPUT");
4992
4993 /* Init... */
4994 if (t == ctl->t_start || !init) {
4995 init = 1;
4996
4997 /* Read meteo data... */
4998 get_met_filename(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
4999 ctl->metbase, ctl->dt_met, filename);
5000 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5001 ERRMSG("Cannot open file!");
5002
5003 get_met_filename(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
5004 ctl->metbase, ctl->dt_met, filename);
5005 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5006 ERRMSG("Cannot open file!");
5007
5008 /* Update GPU... */
5009 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
5010 SELECT_TIMER("GET_MET", "INPUT");
5011
5012 /* Caching... */
5013 if (ctl->met_cache && t != ctl->t_stop) {
5014 get_met_filename(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
5015 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
5016 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5017 LOG(1, "Caching: %s", cachefile);
5018 if (system(cmd) != 0)
5019 WARN("Caching command failed!");
5020 }
5021 }
5022
5023 /* Read new data for forward trajectories... */
5024 if (t > (*met1)->time) {
5025
5026 /* Pointer swap... */
5027 mets = *met1;
5028 *met1 = *met0;
5029 *met0 = mets;
5030
5031 /* Read new meteo data... */
5032 get_met_filename(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
5033 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5034 ERRMSG("Cannot open file!");
5035
5036 /* Update GPU... */
5037 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
5038 SELECT_TIMER("GET_MET", "INPUT");
5039
5040 /* Caching... */
5041 if (ctl->met_cache && t != ctl->t_stop) {
5042 get_met_filename(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
5043 cachefile);
5044 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5045 LOG(1, "Caching: %s", cachefile);
5046 if (system(cmd) != 0)
5047 WARN("Caching command failed!");
5048 }
5049 }
5050
5051 /* Read new data for backward trajectories... */
5052 if (t < (*met0)->time) {
5053
5054 /* Pointer swap... */
5055 mets = *met1;
5056 *met1 = *met0;
5057 *met0 = mets;
5058
5059 /* Read new meteo data... */
5060 get_met_filename(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
5061 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5062 ERRMSG("Cannot open file!");
5063
5064 /* Update GPU... */
5065 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
5066 SELECT_TIMER("GET_MET", "INPUT");
5067
5068 /* Caching... */
5069 if (ctl->met_cache && t != ctl->t_stop) {
5070 get_met_filename(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
5071 cachefile);
5072 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5073 LOG(1, "Caching: %s", cachefile);
5074 if (system(cmd) != 0)
5075 WARN("Caching command failed!");
5076 }
5077 }
5078
5079 /* Check that grids are consistent... */
5080 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
5081 if ((*met0)->nx != (*met1)->nx
5082 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
5083 ERRMSG("Meteo grid dimensions do not match!");
5084 for (int ix = 0; ix < (*met0)->nx; ix++)
5085 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
5086 ERRMSG("Meteo grid longitudes do not match!");
5087 for (int iy = 0; iy < (*met0)->ny; iy++)
5088 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
5089 ERRMSG("Meteo grid latitudes do not match!");
5090 for (int ip = 0; ip < (*met0)->np; ip++)
5091 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
5092 ERRMSG("Meteo grid pressure levels do not match!");
5093 }
5094}
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:1692
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:6151
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2069
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2702
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2534
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 5098 of file mptrac.c.

5103 {
5104
5105 /* Initialize timesteps... */
5106 module_timesteps_init(ctl, atm);
5107
5108 /* Initialize random number generator... */
5109 module_rng_init(ntask);
5110
5111 /* Update GPU memory... */
5112 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
5113}
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4650
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:4326
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 5117 of file mptrac.c.

5120 {
5121
5122 int result;
5123
5124 /* Set timer... */
5125 SELECT_TIMER("READ_ATM", "INPUT");
5126
5127 /* Init... */
5128 atm->np = 0;
5129
5130 /* Write info... */
5131 LOG(1, "Read atmospheric data: %s", filename);
5132
5133 /* Read ASCII data... */
5134 if (ctl->atm_type == 0)
5135 result = read_atm_asc(filename, ctl, atm);
5136
5137 /* Read binary data... */
5138 else if (ctl->atm_type == 1)
5139 result = read_atm_bin(filename, ctl, atm);
5140
5141 /* Read netCDF data... */
5142 else if (ctl->atm_type == 2)
5143 result = read_atm_nc(filename, ctl, atm);
5144
5145 /* Read CLaMS data... */
5146 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
5147 result = read_atm_clams(filename, ctl, atm);
5148
5149 /* Error... */
5150 else
5151 ERRMSG("Atmospheric data type not supported!");
5152
5153 /* Check result... */
5154 if (result != 1)
5155 return 0;
5156
5157 /* Check number of air parcels... */
5158 if (atm->np < 1)
5159 ERRMSG("Can not read any data!");
5160
5161 /* Write info... */
5162 double mini, maxi;
5163 LOG(2, "Number of particles: %d", atm->np);
5164 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5165 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5166 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5167 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5168 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5169 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5170 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5171 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5172 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5173 for (int iq = 0; iq < ctl->nq; iq++) {
5174 char msg[5 * LEN];
5175 sprintf(msg, "Quantity %s range: %s ... %s %s",
5176 ctl->qnt_name[iq], ctl->qnt_format[iq],
5177 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5178 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5179 LOG(2, msg, mini, maxi);
5180 }
5181
5182 /* Return success... */
5183 return 1;
5184}
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:6925
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:6809
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:6865
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:6767
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2209
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3007
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2206
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2200
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 5188 of file mptrac.c.

5190 {
5191
5192 /* Set timer... */
5193 SELECT_TIMER("READ_CLIM", "INPUT");
5194
5195 /* Init tropopause climatology... */
5196 clim_tropo_init(clim);
5197
5198 /* Read photolysis rates... */
5199 if (ctl->clim_photo[0] != '-')
5200 read_clim_photo(ctl->clim_photo, &clim->photo);
5201
5202 /* Read HNO3 climatology... */
5203 if (ctl->clim_hno3_filename[0] != '-')
5204 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
5205
5206 /* Read OH climatology... */
5207 if (ctl->clim_oh_filename[0] != '-') {
5208 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
5209 if (ctl->oh_chem_beta > 0)
5210 clim_oh_diurnal_correction(ctl, clim);
5211 }
5212
5213 /* Read H2O2 climatology... */
5214 if (ctl->clim_h2o2_filename[0] != '-')
5215 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
5216
5217 /* Read HO2 climatology... */
5218 if (ctl->clim_ho2_filename[0] != '-')
5219 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
5220
5221 /* Read O(1D) climatology... */
5222 if (ctl->clim_o1d_filename[0] != '-')
5223 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
5224
5225 /* Read CFC-10 time series... */
5226 if (ctl->clim_ccl4_timeseries[0] != '-')
5228
5229 /* Read CFC-11 time series... */
5230 if (ctl->clim_ccl3f_timeseries[0] != '-')
5232
5233 /* Read CFC-12 time series... */
5234 if (ctl->clim_ccl2f2_timeseries[0] != '-')
5236
5237 /* Read N2O time series... */
5238 if (ctl->clim_n2o_timeseries[0] != '-')
5239 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
5240
5241 /* Read SF6 time series... */
5242 if (ctl->clim_sf6_timeseries[0] != '-')
5243 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
5244}
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:6958
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:7077
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:7131
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:232
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:115
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2834
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2837
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2822
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2831
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2828
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2825
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 5248 of file mptrac.c.

5252 {
5253
5254 /* Set timer... */
5255 SELECT_TIMER("READ_CTL", "INPUT");
5256
5257 /* Write info... */
5258 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
5259 "(executable: %s | version: %s | compiled: %s, %s)\n",
5260 argv[0], VERSION, __DATE__, __TIME__);
5261
5262 /* Initialize quantity indices... */
5263 ctl->qnt_idx = -1;
5264 ctl->qnt_ens = -1;
5265 ctl->qnt_stat = -1;
5266 ctl->qnt_m = -1;
5267 ctl->qnt_vmr = -1;
5268 ctl->qnt_rp = -1;
5269 ctl->qnt_rhop = -1;
5270 ctl->qnt_ps = -1;
5271 ctl->qnt_ts = -1;
5272 ctl->qnt_zs = -1;
5273 ctl->qnt_us = -1;
5274 ctl->qnt_vs = -1;
5275 ctl->qnt_ess = -1;
5276 ctl->qnt_nss = -1;
5277 ctl->qnt_shf = -1;
5278 ctl->qnt_lsm = -1;
5279 ctl->qnt_sst = -1;
5280 ctl->qnt_pbl = -1;
5281 ctl->qnt_pt = -1;
5282 ctl->qnt_tt = -1;
5283 ctl->qnt_zt = -1;
5284 ctl->qnt_h2ot = -1;
5285 ctl->qnt_zg = -1;
5286 ctl->qnt_p = -1;
5287 ctl->qnt_t = -1;
5288 ctl->qnt_rho = -1;
5289 ctl->qnt_u = -1;
5290 ctl->qnt_v = -1;
5291 ctl->qnt_w = -1;
5292 ctl->qnt_h2o = -1;
5293 ctl->qnt_o3 = -1;
5294 ctl->qnt_lwc = -1;
5295 ctl->qnt_rwc = -1;
5296 ctl->qnt_iwc = -1;
5297 ctl->qnt_swc = -1;
5298 ctl->qnt_cc = -1;
5299 ctl->qnt_pct = -1;
5300 ctl->qnt_pcb = -1;
5301 ctl->qnt_cl = -1;
5302 ctl->qnt_plcl = -1;
5303 ctl->qnt_plfc = -1;
5304 ctl->qnt_pel = -1;
5305 ctl->qnt_cape = -1;
5306 ctl->qnt_cin = -1;
5307 ctl->qnt_o3c = -1;
5308 ctl->qnt_hno3 = -1;
5309 ctl->qnt_oh = -1;
5310 ctl->qnt_h2o2 = -1;
5311 ctl->qnt_ho2 = -1;
5312 ctl->qnt_o1d = -1;
5313 ctl->qnt_mloss_oh = -1;
5314 ctl->qnt_mloss_h2o2 = -1;
5315 ctl->qnt_mloss_kpp = -1;
5316 ctl->qnt_mloss_wet = -1;
5317 ctl->qnt_mloss_dry = -1;
5318 ctl->qnt_mloss_decay = -1;
5319 ctl->qnt_loss_rate = -1;
5320 ctl->qnt_psat = -1;
5321 ctl->qnt_psice = -1;
5322 ctl->qnt_pw = -1;
5323 ctl->qnt_sh = -1;
5324 ctl->qnt_rh = -1;
5325 ctl->qnt_rhice = -1;
5326 ctl->qnt_theta = -1;
5327 ctl->qnt_zeta = -1;
5328 ctl->qnt_zeta_d = -1;
5329 ctl->qnt_zeta_dot = -1;
5330 ctl->qnt_eta = -1;
5331 ctl->qnt_eta_dot = -1;
5332 ctl->qnt_tvirt = -1;
5333 ctl->qnt_lapse = -1;
5334 ctl->qnt_vh = -1;
5335 ctl->qnt_vz = -1;
5336 ctl->qnt_pv = -1;
5337 ctl->qnt_tdew = -1;
5338 ctl->qnt_tice = -1;
5339 ctl->qnt_tsts = -1;
5340 ctl->qnt_tnat = -1;
5341 ctl->qnt_Cx = -1;
5342 ctl->qnt_Ch2o = -1;
5343 ctl->qnt_Co3 = -1;
5344 ctl->qnt_Cco = -1;
5345 ctl->qnt_Coh = -1;
5346 ctl->qnt_Ch = -1;
5347 ctl->qnt_Cho2 = -1;
5348 ctl->qnt_Ch2o2 = -1;
5349 ctl->qnt_Co1d = -1;
5350 ctl->qnt_Co3p = -1;
5351 ctl->qnt_Cccl4 = -1;
5352 ctl->qnt_Cccl3f = -1;
5353 ctl->qnt_Cccl2f2 = -1;
5354 ctl->qnt_Cn2o = -1;
5355 ctl->qnt_Csf6 = -1;
5356 ctl->qnt_aoa = -1;
5357 ctl->qnt_Arn222 = -1;
5358 ctl->qnt_Apb210 = -1;
5359 ctl->qnt_Abe7 = -1;
5360 ctl->qnt_Acs137 = -1;
5361 ctl->qnt_Ai131 = -1;
5362 ctl->qnt_Axe133 = -1;
5363 ctl->qnt_subdomain = -1;
5364 ctl->qnt_destination = -1;
5365
5366 /* Read quantities... */
5367 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
5368 if (ctl->nq > NQ)
5369 ERRMSG("Too many quantities!");
5370 for (int iq = 0; iq < ctl->nq; iq++) {
5371
5372 /* Read quantity name and format... */
5373 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
5374 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
5375 ctl->qnt_longname[iq]);
5376 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
5377 ctl->qnt_format[iq]);
5378 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
5379 sprintf(ctl->qnt_format[iq], "%%.2f");
5380
5381 /* Try to identify quantity... */
5382 SET_QNT(qnt_idx, "idx", "particle index", "-")
5383 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
5384 SET_QNT(qnt_stat, "stat", "station flag", "-")
5385 SET_QNT(qnt_m, "m", "mass", "kg")
5386 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
5387 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
5388 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
5389 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
5390 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
5391 SET_QNT(qnt_zs, "zs", "surface height", "km")
5392 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
5393 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
5394 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
5395 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
5396 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
5397 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
5398 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
5399 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
5400 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
5401 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
5402 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
5403 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
5404 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
5405 SET_QNT(qnt_p, "p", "pressure", "hPa")
5406 SET_QNT(qnt_t, "t", "temperature", "K")
5407 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
5408 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
5409 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
5410 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
5411 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
5412 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
5413 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
5414 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
5415 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
5416 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
5417 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
5418 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
5419 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
5420 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
5421 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
5422 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
5423 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
5424 SET_QNT(qnt_cape, "cape", "convective available potential energy",
5425 "J/kg")
5426 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
5427 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
5428 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
5429 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
5430 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
5431 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
5432 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
5433 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
5434 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
5435 "mass loss due to H2O2 chemistry", "kg")
5436 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
5437 "kg")
5438 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
5439 "kg")
5440 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
5441 "kg")
5442 SET_QNT(qnt_mloss_decay, "mloss_decay",
5443 "mass loss due to exponential decay", "kg")
5444 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
5445 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
5446 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
5447 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
5448 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
5449 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
5450 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
5451 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
5452 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
5453 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
5454 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
5455 "K/day")
5456 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
5457 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
5458 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
5459 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
5460 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
5461 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
5462 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
5463 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
5464 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
5465 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
5466 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
5467 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
5468 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
5469 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
5470 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
5471 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
5472 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
5473 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
5474 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
5475 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
5476 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
5477 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
5478 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
5479 "ppv")
5480 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
5481 "ppv")
5482 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
5483 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
5484 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
5485 SET_QNT(qnt_Arn222, "Arn222", "Rn-222 activity", "Bq")
5486 SET_QNT(qnt_Apb210, "Apb210", "Pb-210 activity", "Bq")
5487 SET_QNT(qnt_Abe7, "Abe7", "Be-7 activity", "Bq")
5488 SET_QNT(qnt_Acs137, "Acs137", "Cs-137 activity", "Bq")
5489 SET_QNT(qnt_Ai131, "Ai131", "I-131 activity", "Bq")
5490 SET_QNT(qnt_Axe133, "Axe133", "Xe-133 activity", "Bq")
5491 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
5492 SET_QNT(qnt_destination, "destination",
5493 "subdomain index of destination", "-")
5494 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
5495 }
5496
5497 /* Vertical coordinate and velocity... */
5498 ctl->advect_vert_coord =
5499 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
5500 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
5501 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
5502
5503 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
5504 ERRMSG("Add quantity zeta for diabatic advection!");
5505 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
5506 ERRMSG("Add quantity eta for etadot avection!");
5507
5508 ctl->met_vert_coord =
5509 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
5510 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
5511 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
5512
5513 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
5514 ERRMSG
5515 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
5516 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
5517 ERRMSG
5518 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
5519
5520 /* Time steps of simulation... */
5521 ctl->direction =
5522 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
5523 if (ctl->direction != -1 && ctl->direction != 1)
5524 ERRMSG("Set DIRECTION to -1 or 1!");
5525 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
5526 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
5527
5528 /* Meteo data... */
5529 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
5530 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
5531 ctl->met_convention =
5532 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
5533 ctl->met_type =
5534 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
5535 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
5536 ERRMSG
5537 ("Please use meteo files in netcdf format for diabatic calculations.");
5538 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
5539 ERRMSG
5540 ("Please use meteo files in netcdf format for etadot calculations.");
5541 ctl->met_clams =
5542 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
5543 ctl->met_nc_scale =
5544 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
5545 ctl->met_nc_level =
5546 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
5547 ctl->met_nc_quant =
5548 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
5549 ctl->met_zstd_level =
5550 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
5551 for (int i = 0; i < METVAR; i++) {
5552 char defprec[LEN] = "0", deftol[LEN] = "0.0";
5553 if (i == 0) /* geopotential height */
5554 sprintf(deftol, "0.5");
5555 else if (i == 1) /* temperature */
5556 sprintf(deftol, "5.0");
5557 else /* other variables */
5558 sprintf(defprec, "8");
5559 ctl->met_comp_prec[i] =
5560 (int) scan_ctl(filename, argc, argv, "MET_COMP_PREC", i, defprec, NULL);
5561 ctl->met_comp_tol[i] =
5562 scan_ctl(filename, argc, argv, "MET_COMP_TOL", i, deftol, NULL);
5563 }
5564 ctl->met_cms_batch =
5565 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
5566 ctl->met_cms_zstd =
5567 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
5568 ctl->met_cms_nd0x =
5569 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
5570 ctl->met_cms_nd0y =
5571 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
5572 ctl->met_cms_maxlev =
5573 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
5574 ctl->met_cms_eps_z =
5575 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
5576 ctl->met_cms_eps_t =
5577 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
5578 ctl->met_cms_eps_u =
5579 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
5580 ctl->met_cms_eps_v =
5581 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
5582 ctl->met_cms_eps_w =
5583 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
5584 ctl->met_cms_eps_pv =
5585 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
5586 ctl->met_cms_eps_h2o =
5587 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
5588 ctl->met_cms_eps_o3 =
5589 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5590 ctl->met_cms_eps_lwc =
5591 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5592 ctl->met_cms_eps_rwc =
5593 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5594 ctl->met_cms_eps_iwc =
5595 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5596 ctl->met_cms_eps_swc =
5597 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5598 ctl->met_cms_eps_cc =
5599 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5600 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5601 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5602 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5603 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5604 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5605 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5606 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5607 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5608 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5609 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5610 ctl->met_detrend =
5611 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5612 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5613 if (ctl->met_np > EP)
5614 ERRMSG("Too many pressure levels!");
5615 ctl->met_press_level_def =
5616 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5617 NULL);
5618 if (ctl->met_press_level_def >= 0) {
5619 level_definitions(ctl);
5620 } else {
5621 if (ctl->met_np > 0) {
5622 for (int ip = 0; ip < ctl->met_np; ip++)
5623 ctl->met_p[ip] =
5624 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5625 }
5626 }
5627 ctl->met_nlev =
5628 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
5629 if (ctl->met_nlev > EP)
5630 ERRMSG("Too many model levels!");
5631 for (int ip = 0; ip < ctl->met_nlev; ip++)
5632 ctl->met_lev_hyam[ip] =
5633 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
5634 for (int ip = 0; ip < ctl->met_nlev; ip++)
5635 ctl->met_lev_hybm[ip] =
5636 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
5637 ctl->met_geopot_sx =
5638 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5639 ctl->met_geopot_sy =
5640 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5641 ctl->met_relhum =
5642 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5643 ctl->met_cape =
5644 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
5645 if (ctl->met_cape < 0 || ctl->met_cape > 1)
5646 ERRMSG("Set MET_CAPE to 0 or 1!");
5647 ctl->met_pbl =
5648 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
5649 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
5650 ERRMSG("Set MET_PBL to 0 ... 3!");
5651 ctl->met_pbl_min =
5652 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
5653 ctl->met_pbl_max =
5654 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
5655 ctl->met_tropo =
5656 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5657 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5658 ERRMSG("Set MET_TROPO to 0 ... 5!");
5659 ctl->met_tropo_pv =
5660 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5661 ctl->met_tropo_theta =
5662 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5663 ctl->met_tropo_spline =
5664 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5665 ctl->met_dt_out =
5666 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5667 ctl->met_cache =
5668 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5669 ctl->met_mpi_share =
5670 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5671
5672 /* Sorting... */
5673 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5674
5675 /* Isosurface parameters... */
5676 ctl->isosurf =
5677 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5678 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5679
5680 /* Random number generator... */
5681 ctl->rng_type =
5682 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
5683 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5684 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5685
5686 /* Advection parameters... */
5687 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
5688 if (!
5689 (ctl->advect == 0 || ctl->advect == 1 || ctl->advect == 2
5690 || ctl->advect == 4))
5691 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
5692
5693 /* Diffusion parameters... */
5694 ctl->diffusion
5695 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
5696 if (ctl->diffusion < 0 || ctl->diffusion > 2)
5697 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
5698 ctl->turb_dx_pbl =
5699 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
5700 ctl->turb_dx_trop =
5701 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5702 ctl->turb_dx_strat =
5703 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5704 ctl->turb_dz_pbl =
5705 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
5706 ctl->turb_dz_trop =
5707 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5708 ctl->turb_dz_strat =
5709 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5710 ctl->turb_mesox =
5711 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5712 ctl->turb_mesoz =
5713 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5714
5715 /* Convection... */
5716 ctl->conv_mix_pbl
5717 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5718 ctl->conv_pbl_trans
5719 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5720 ctl->conv_cape
5721 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5722 ctl->conv_cin
5723 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5724 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5725
5726 /* Boundary conditions... */
5727 ctl->bound_mass =
5728 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5729 ctl->bound_mass_trend =
5730 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5731 ctl->bound_vmr =
5732 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5733 ctl->bound_vmr_trend =
5734 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5735 ctl->bound_lat0 =
5736 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5737 ctl->bound_lat1 =
5738 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5739 ctl->bound_p0 =
5740 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5741 ctl->bound_p1 =
5742 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5743 ctl->bound_dps =
5744 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5745 ctl->bound_dzs =
5746 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5747 ctl->bound_zetas =
5748 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5749 ctl->bound_pbl =
5750 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5751
5752 /* Species parameters... */
5753 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5754 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5755 ctl->molmass = 120.907;
5756 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5757 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5758 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5759 ctl->molmass = 137.359;
5760 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5761 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5762 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5763 ctl->molmass = 16.043;
5764 ctl->oh_chem_reaction = 2;
5765 ctl->oh_chem[0] = 2.45e-12;
5766 ctl->oh_chem[1] = 1775;
5767 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5768 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5769 } else if (strcasecmp(ctl->species, "CO") == 0) {
5770 ctl->molmass = 28.01;
5771 ctl->oh_chem_reaction = 3;
5772 ctl->oh_chem[0] = 6.9e-33;
5773 ctl->oh_chem[1] = 2.1;
5774 ctl->oh_chem[2] = 1.1e-12;
5775 ctl->oh_chem[3] = -1.3;
5776 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5777 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5778 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5779 ctl->molmass = 44.009;
5780 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5781 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5782 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5783 ctl->molmass = 18.01528;
5784 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5785 ctl->molmass = 44.013;
5786 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5787 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5788 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5789 ctl->molmass = 17.031;
5790 ctl->oh_chem_reaction = 2;
5791 ctl->oh_chem[0] = 1.7e-12;
5792 ctl->oh_chem[1] = 710;
5793 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5794 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5795 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5796 ctl->molmass = 63.012;
5797 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5798 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5799 } else if (strcasecmp(ctl->species, "NO") == 0) {
5800 ctl->molmass = 30.006;
5801 ctl->oh_chem_reaction = 3;
5802 ctl->oh_chem[0] = 7.1e-31;
5803 ctl->oh_chem[1] = 2.6;
5804 ctl->oh_chem[2] = 3.6e-11;
5805 ctl->oh_chem[3] = 0.1;
5806 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5807 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5808 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5809 ctl->molmass = 46.005;
5810 ctl->oh_chem_reaction = 3;
5811 ctl->oh_chem[0] = 1.8e-30;
5812 ctl->oh_chem[1] = 3.0;
5813 ctl->oh_chem[2] = 2.8e-11;
5814 ctl->oh_chem[3] = 0.0;
5815 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5816 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5817 } else if (strcasecmp(ctl->species, "O3") == 0) {
5818 ctl->molmass = 47.997;
5819 ctl->oh_chem_reaction = 2;
5820 ctl->oh_chem[0] = 1.7e-12;
5821 ctl->oh_chem[1] = 940;
5822 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5823 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5824 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5825 ctl->molmass = 146.048;
5826 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5827 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5828 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5829 ctl->molmass = 64.066;
5830 ctl->oh_chem_reaction = 3;
5831 ctl->oh_chem[0] = 2.9e-31;
5832 ctl->oh_chem[1] = 4.1;
5833 ctl->oh_chem[2] = 1.7e-12;
5834 ctl->oh_chem[3] = -0.2;
5835 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5836 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5837 }
5838
5839 /* Molar mass... */
5840 char defstr[LEN];
5841 sprintf(defstr, "%g", ctl->molmass);
5842 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5843
5844 /* OH chemistry... */
5845 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5846 ctl->oh_chem_reaction =
5847 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5848 NULL);
5849 for (int ip = 0; ip < 4; ip++) {
5850 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5851 ctl->oh_chem[ip] =
5852 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5853 }
5854 ctl->oh_chem_beta =
5855 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5856
5857 /* H2O2 chemistry... */
5858 ctl->h2o2_chem_reaction =
5859 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5860
5861 /* KPP chemistry... */
5862 ctl->kpp_chem =
5863 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5864 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5865
5866 /* First order tracer chemistry... */
5867 ctl->tracer_chem =
5868 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5869
5870 /* Radioactive decay... */
5871 ctl->radio_decay =
5872 (int) scan_ctl(filename, argc, argv, "RADIO_DECAY", -1, "0", NULL);
5873
5874 /* Wet deposition... */
5875 for (int ip = 0; ip < 2; ip++) {
5876 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5877 ctl->wet_depo_ic_h[ip] =
5878 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5879 }
5880 for (int ip = 0; ip < 1; ip++) {
5881 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5882 ctl->wet_depo_bc_h[ip] =
5883 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5884 }
5885 ctl->wet_depo_so2_ph =
5886 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
5887 ctl->wet_depo_ic_a =
5888 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5889 ctl->wet_depo_ic_b =
5890 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5891 ctl->wet_depo_bc_a =
5892 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5893 ctl->wet_depo_bc_b =
5894 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5895 ctl->wet_depo_pre[0] =
5896 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5897 ctl->wet_depo_pre[1] =
5898 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5900 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5902 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5903
5904 /* Dry deposition... */
5905 ctl->dry_depo_vdep =
5906 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5907 ctl->dry_depo_dp =
5908 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5909
5910 /* Climatological data... */
5911 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5912 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5913 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5914 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5915 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5916 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5917 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5918 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5919 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5920 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5921 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5922 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5923 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5924 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5925 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5926 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5927 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5928 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5929 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5930 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5931 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5932 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5933
5934 /* Mixing... */
5935 ctl->mixing_dt =
5936 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5937 ctl->mixing_trop =
5938 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5939 ctl->mixing_strat =
5940 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5941 ctl->mixing_z0 =
5942 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5943 ctl->mixing_z1 =
5944 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5945 ctl->mixing_nz =
5946 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5947 ctl->mixing_lon0 =
5948 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5949 ctl->mixing_lon1 =
5950 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5951 ctl->mixing_nx =
5952 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5953 ctl->mixing_lat0 =
5954 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5955 ctl->mixing_lat1 =
5956 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5957 ctl->mixing_ny =
5958 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5959
5960 /* Chemistry grid... */
5961 ctl->chemgrid_z0 =
5962 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5963 ctl->chemgrid_z1 =
5964 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5965 ctl->chemgrid_nz =
5966 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5967 ctl->chemgrid_lon0 =
5968 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5969 ctl->chemgrid_lon1 =
5970 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5971 ctl->chemgrid_nx =
5972 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5973 ctl->chemgrid_lat0 =
5974 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5975 ctl->chemgrid_lat1 =
5976 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5977 ctl->chemgrid_ny =
5978 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5979
5980 /* Exponential decay... */
5981 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5982 ctl->tdec_strat =
5983 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5984
5985 /* PSC analysis... */
5986 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5987 ctl->psc_hno3 =
5988 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5989
5990 /* Output of atmospheric data... */
5991 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5992 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5993 ctl->atm_dt_out =
5994 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5995 ctl->atm_filter =
5996 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5997 ctl->atm_stride =
5998 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5999 ctl->atm_type =
6000 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
6001 ctl->atm_type_out =
6002 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
6003 if (ctl->atm_type_out == -1)
6004 ctl->atm_type_out = ctl->atm_type;
6005 ctl->atm_nc_level =
6006 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
6007 for (int iq = 0; iq < ctl->nq; iq++)
6008 ctl->atm_nc_quant[iq] =
6009 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
6010 ctl->obs_type =
6011 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
6012
6013 /* Output of CSI data... */
6014 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
6015 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
6016 ctl->csi_dt_out =
6017 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
6018 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
6019 ctl->csi_obsmin =
6020 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
6021 ctl->csi_modmin =
6022 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
6023 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
6024 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
6025 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
6026 ctl->csi_lon0 =
6027 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
6028 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
6029 ctl->csi_nx =
6030 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
6031 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
6032 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
6033 ctl->csi_ny =
6034 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
6035
6036 /* Output of ensemble data... */
6037 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
6038 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
6039 ctl->ens_dt_out =
6040 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
6041
6042 /* Output of grid data... */
6043 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
6044 ctl->grid_basename);
6045 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
6046 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
6047 ctl->grid_dt_out =
6048 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
6049 ctl->grid_sparse =
6050 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
6051 ctl->grid_nc_level =
6052 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
6053 for (int iq = 0; iq < ctl->nq; iq++)
6054 ctl->grid_nc_quant[iq] =
6055 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
6056 ctl->grid_stddev =
6057 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
6058 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
6059 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
6060 ctl->grid_nz =
6061 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
6062 ctl->grid_lon0 =
6063 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
6064 ctl->grid_lon1 =
6065 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
6066 ctl->grid_nx =
6067 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
6068 ctl->grid_lat0 =
6069 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
6070 ctl->grid_lat1 =
6071 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
6072 ctl->grid_ny =
6073 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
6074 ctl->grid_type =
6075 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
6076
6077 /* Output of profile data... */
6078 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
6079 ctl->prof_basename);
6080 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
6081 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
6082 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
6083 ctl->prof_nz =
6084 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
6085 ctl->prof_lon0 =
6086 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
6087 ctl->prof_lon1 =
6088 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
6089 ctl->prof_nx =
6090 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
6091 ctl->prof_lat0 =
6092 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
6093 ctl->prof_lat1 =
6094 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
6095 ctl->prof_ny =
6096 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
6097
6098 /* Output of sample data... */
6099 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
6100 ctl->sample_basename);
6101 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
6102 ctl->sample_kernel);
6103 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
6104 ctl->sample_obsfile);
6105 ctl->sample_dx =
6106 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
6107 ctl->sample_dz =
6108 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
6109
6110 /* Output of station data... */
6111 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
6112 ctl->stat_basename);
6113 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
6114 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
6115 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
6116 ctl->stat_t0 =
6117 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
6118 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
6119
6120 /* Output of VTK data... */
6121 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
6122 ctl->vtk_dt_out =
6123 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
6124 ctl->vtk_stride =
6125 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
6126 ctl->vtk_scale =
6127 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
6128 ctl->vtk_offset =
6129 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
6130 ctl->vtk_sphere =
6131 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
6132
6133 /* Domain decomposition... */
6134 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
6136 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
6137 (ctl->dd == 1) ? "2" : "1", NULL);
6138 ctl->dd_subdomains_zonal =
6139 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
6140 (ctl->dd == 1) ? "2" : "1", NULL);
6142 ctl->dd = 1;
6143 else if (ctl->dd == 1)
6144 ERRMSG("Please provide zonal and meridional subdomain numbers!");
6145 ctl->dd_halos_size =
6146 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
6147}
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:2371
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:10745
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:350
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:360
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1699
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3105
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2302
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3066
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3033
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2335
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3042
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2281
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3229
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2994
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2314
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3036
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2323
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3057
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2290
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3183
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2712
double stat_r
Search radius around station [km].
Definition: mptrac.h:3189
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3060
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3213
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2680
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2311
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2602
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2389
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3132
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3108
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2632
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2699
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2353
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2425
char species[LEN]
Species.
Definition: mptrac.h:2810
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3051
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3063
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2677
double met_comp_tol[METVAR]
Compression tolerance for SZ3 or ZFP.
Definition: mptrac.h:2569
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2305
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3093
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3111
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3123
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2236
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2605
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2332
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3114
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2359
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2696
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3168
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2419
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2668
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3084
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2593
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2257
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2401
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3195
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3027
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3129
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3054
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2263
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3099
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2386
int radio_decay
Switch for radioactive decay module (0=off, 1=on).
Definition: mptrac.h:2942
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2665
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2638
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2233
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3135
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2239
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3138
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3030
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2674
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3039
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2635
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2617
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2620
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3081
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2596
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3141
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2296
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2690
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3147
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2218
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2705
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2428
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2356
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3048
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3192
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3220
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3012
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2578
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2656
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2936
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3024
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2254
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2245
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3201
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2771
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3171
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2347
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3078
int met_comp_prec[METVAR]
Compression precision for SZ3 or ZFP.
Definition: mptrac.h:2566
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2275
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2395
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2623
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2683
int met_dx
Stride for longitudes.
Definition: mptrac.h:2626
int qnt_destination
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2515
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2407
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2939
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2732
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2278
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3210
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2293
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2350
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2299
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3156
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2398
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2287
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3177
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3021
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3096
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2611
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2242
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2587
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3117
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2991
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2266
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2326
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3144
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2659
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2284
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3000
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2933
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3072
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3045
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2422
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3186
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3120
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2644
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2590
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2338
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2581
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2344
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3102
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2251
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3075
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3165
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3003
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2671
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2997
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3162
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2572
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2981
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2641
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3150
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2320
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2368
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2383
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2662
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3159
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2341
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2984
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3153
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2614
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2930
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3018
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2608
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2575
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2584
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3090
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3198
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2269
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2858
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3207
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2599
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2431
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2260
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3015
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2392
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2248
int met_dy
Stride for latitudes.
Definition: mptrac.h:2629
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3223
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2212
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2693
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2308
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2203
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3174
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3204
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3180
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3126
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3226
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2272
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2317
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2329
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3087
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2434
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 7, 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 6151 of file mptrac.c.

6156 {
6157
6158 /* Write info... */
6159 LOG(1, "Read meteo data: %s", filename);
6160
6161 /* Set rank... */
6162 int rank = 0;
6163#ifdef MPI
6164 if (ctl->met_mpi_share)
6165 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
6166#endif
6167
6168 /* Check rank... */
6169 if (!ctl->met_mpi_share || rank == 0) {
6170
6171 /* Read netCDF data... */
6172 if (ctl->met_type == 0) {
6173 if (read_met_nc(filename, ctl, met, dd) != 1)
6174 return 0;
6175 }
6176
6177 /* Read binary data... */
6178 else if ((ctl->met_type >= 1 && ctl->met_type <= 5) || ctl->met_type == 7) {
6179 if (read_met_bin(filename, ctl, met) != 1)
6180 return 0;
6181 }
6182
6183#ifdef ECCODES
6184 /* Read grib data... */
6185 else if (ctl->met_type == 6) {
6186 if (read_met_grib(filename, ctl, met) != 1)
6187 return 0;
6188 }
6189#endif
6190
6191 /* Not implemented... */
6192 else
6193 ERRMSG("MET_TYPE not implemented!");
6194
6195 /* Preprocessing for netCDF and grib files... */
6196 if (ctl->met_type == 0 || ctl->met_type == 6) {
6197
6198 /* Extrapolate data for lower boundary... */
6200
6201 /* Fix polar winds... */
6203
6204 /* Create periodic boundary conditions... */
6205#ifndef DD
6206 read_met_periodic(met);
6207#endif
6208
6209 /* Downsampling... */
6210 read_met_sample(ctl, met);
6211
6212 /* Calculate geopotential heights... */
6213 read_met_geopot(ctl, met);
6214
6215 /* Calculate potential vorticity... */
6216 read_met_pv(met);
6217
6218 /* Calculate boundary layer data... */
6219 read_met_pbl(ctl, met);
6220
6221 /* Calculate tropopause data... */
6222 read_met_tropo(ctl, clim, met);
6223
6224 /* Calculate cloud properties... */
6225 read_met_cloud(met);
6226
6227 /* Calculate convective available potential energy... */
6228 read_met_cape(ctl, clim, met);
6229
6230 /* Calculate total column ozone... */
6231 read_met_ozone(met);
6232
6233 /* Detrending... */
6234 read_met_detrend(ctl, met);
6235
6236 /* Check meteo data and smooth zeta profiles ... */
6237 read_met_monotonize(ctl, met);
6238 }
6239 }
6240
6241 /* Broadcast data via MPI... */
6242#ifdef MPI
6243 if (ctl->met_mpi_share) {
6244
6245 /* Set timer... */
6246 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM");
6247 LOG(2, "Broadcast data on rank %d...", rank);
6248
6249 /* Broadcast... */
6250 broadcast_large_data(met, sizeof(met_t));
6251 }
6252#endif
6253
6254 /* Return success... */
6255 return 1;
6256}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:7870
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:7830
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:10299
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:7669
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:9907
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:7726
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:9606
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:10044
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:9691
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:10270
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:10164
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:7271
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:10105
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:7554
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 6260 of file mptrac.c.

6268 {
6269
6270 /* Initialize modules... */
6271 if (t == ctl->t_start) {
6272
6273 /* Initialize isosurface data... */
6274 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6275 module_isosurf_init(ctl, cache, *met0, *met1, atm);
6276
6277 /* Initialize advection... */
6278 module_advect_init(ctl, cache, *met0, *met1, atm);
6279
6280 /* Initialize chemistry... */
6281 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
6282 }
6283
6284 /* Set time steps of air parcels... */
6285 module_timesteps(ctl, cache, *met0, atm, t);
6286
6287 /* Sort particles... */
6288 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
6289 module_sort(ctl, *met0, atm);
6290
6291 /* Check positions (initial)... */
6292 module_position(cache, *met0, *met1, atm);
6293
6294 /* Advection... */
6295 if (ctl->advect > 0)
6296 module_advect(ctl, cache, *met0, *met1, atm);
6297
6298 /* Turbulent diffusion... */
6299 if (ctl->diffusion == 1
6300 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
6301 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
6302 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
6303 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
6304
6305 /* Mesoscale diffusion... */
6306 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
6307 module_diff_meso(ctl, cache, *met0, *met1, atm);
6308
6309 /* Diffusion... */
6310 if (ctl->diffusion == 2)
6311 module_diff_pbl(ctl, cache, *met0, *met1, atm);
6312
6313 /* Convection... */
6314 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
6315 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
6316 module_convection(ctl, cache, *met0, *met1, atm);
6317
6318 /* Sedimentation... */
6319 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
6320 module_sedi(ctl, cache, *met0, *met1, atm);
6321
6322 /* Isosurface... */
6323 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6324 module_isosurf(ctl, cache, *met0, *met1, atm);
6325
6326 /* Check positions (final)... */
6327 module_position(cache, *met0, *met1, atm);
6328
6329 /* Interpolate meteo data... */
6330 if (ctl->met_dt_out > 0
6331 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
6332 module_meteo(ctl, cache, clim, *met0, *met1, atm);
6333
6334 /* Check boundary conditions (initial)... */
6335 if ((ctl->bound_lat0 < ctl->bound_lat1)
6336 && (ctl->bound_p0 > ctl->bound_p1))
6337 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6338
6339 /* Initialize quantity of total loss rate... */
6340 if (ctl->qnt_loss_rate >= 0) {
6341 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
6342 atm->q[ctl->qnt_loss_rate][ip] = 0;
6343 }
6344 }
6345
6346 /* Decay of particle mass... */
6347 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
6348 module_decay(ctl, cache, clim, atm);
6349
6350 /* Interparcel mixing... */
6351 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
6352 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
6353 module_mixing(ctl, clim, atm, t);
6354
6355 /* Calculate the tracer vmr in the chemistry grid... */
6356 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
6357 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
6358 module_chem_grid(ctl, *met0, *met1, atm, t);
6359
6360 /* OH chemistry... */
6361 if (ctl->oh_chem_reaction != 0)
6362 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
6363
6364 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
6365 if (ctl->h2o2_chem_reaction != 0)
6366 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
6367
6368 /* First-order tracer chemistry... */
6369 if (ctl->tracer_chem)
6370 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
6371
6372 /* Radioactive decay... */
6373 if (ctl->radio_decay)
6374 module_radio_decay(ctl, cache, atm);
6375
6376 /* Domain decomposition... */
6377 if (ctl->dd) {
6378#ifdef DD
6379 module_dd(ctl, cache, dd, atm, met0);
6380#else
6381 ERRMSG("Code was compiled without DD!");
6382
6383 /* This will never execute, hack to avoid compilation error... */
6384 LOG(3, "%d", dd->nx_glob);
6385#endif
6386 }
6387
6388 /* KPP chemistry... */
6389 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
6390#ifdef KPP
6391 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
6392#else
6393 ERRMSG("Code was compiled without KPP!");
6394#endif
6395 }
6396
6397 /* Wet deposition... */
6398 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
6399 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
6400 module_wet_depo(ctl, cache, *met0, *met1, atm);
6401
6402 /* Dry deposition... */
6403 if (ctl->dry_depo_vdep > 0)
6404 module_dry_depo(ctl, cache, *met0, *met1, atm);
6405
6406 /* Check boundary conditions (final)... */
6407 if ((ctl->bound_lat0 < ctl->bound_lat1)
6408 && (ctl->bound_p0 > ctl->bound_p1))
6409 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6410}
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:2627
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:4603
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:3852
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:3238
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:3075
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:3959
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:3676
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:4752
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:2913
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:4462
void module_sort(const ctl_t *ctl, const met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:4491
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:3117
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:2817
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:2790
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:4268
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:4217
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:3277
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:3479
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:4681
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:3594
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:3354
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:3746
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:4133
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:3531
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:3676
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 6414 of file mptrac.c.

6420 {
6421
6422 /* Update GPU... */
6423 if (ctl != NULL) {
6424#ifdef _OPENACC
6425 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6426#pragma acc update device(ctl[:1])
6427#endif
6428 }
6429
6430 if (cache != NULL) {
6431#ifdef _OPENACC
6432 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6433#pragma acc update device(cache[:1])
6434#endif
6435 }
6436
6437 if (clim != NULL) {
6438#ifdef _OPENACC
6439 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6440#pragma acc update device(clim[:1])
6441#endif
6442 }
6443
6444 if (met0 != NULL) {
6445#ifdef _OPENACC
6446 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6447 met_t *met0up = *met0;
6448#pragma acc update device(met0up[:1])
6449#endif
6450 }
6451
6452 if (met1 != NULL) {
6453#ifdef _OPENACC
6454 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6455 met_t *met1up = *met1;
6456#pragma acc update device(met1up[:1])
6457#endif
6458 }
6459
6460 if (atm != NULL) {
6461#ifdef _OPENACC
6462 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6463#pragma acc update device(atm[:1])
6464#endif
6465 }
6466}

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

6476 {
6477
6478 /* Update GPU... */
6479 if (ctl != NULL) {
6480#ifdef _OPENACC
6481 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6482#pragma acc update host(ctl[:1])
6483#endif
6484 }
6485
6486 if (cache != NULL) {
6487#ifdef _OPENACC
6488 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6489#pragma acc update host(cache[:1])
6490#endif
6491 }
6492
6493 if (clim != NULL) {
6494#ifdef _OPENACC
6495 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6496#pragma acc update host(clim[:1])
6497#endif
6498 }
6499
6500 if (met0 != NULL) {
6501#ifdef _OPENACC
6502 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6503 met_t *met0up = *met0;
6504#pragma acc update host(met0up[:1])
6505#endif
6506 }
6507
6508 if (met1 != NULL) {
6509#ifdef _OPENACC
6510 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6511 met_t *met1up = *met1;
6512#pragma acc update host(met1up[:1])
6513#endif
6514 }
6515
6516 if (atm != NULL) {
6517#ifdef _OPENACC
6518 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6519#pragma acc update host(atm[:1])
6520#endif
6521 }
6522}

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

6530 {
6531
6532 /* Set timer... */
6533 SELECT_TIMER("WRITE_ATM", "OUTPUT");
6534
6535 /* Write info... */
6536 LOG(1, "Write atmospheric data: %s", filename);
6537
6538 /* Write ASCII data... */
6539 if (ctl->atm_type_out == 0)
6540 write_atm_asc(filename, ctl, atm, t);
6541
6542 /* Write binary data... */
6543 else if (ctl->atm_type_out == 1)
6544 write_atm_bin(filename, ctl, atm);
6545
6546 /* Write netCDF data... */
6547 else if (ctl->atm_type_out == 2)
6548 write_atm_nc(filename, ctl, atm);
6549
6550 /* Write CLaMS trajectory data... */
6551 else if (ctl->atm_type_out == 3)
6552 write_atm_clams_traj(filename, ctl, atm, t);
6553
6554 /* Write CLaMS pos data... */
6555 else if (ctl->atm_type_out == 4)
6556 write_atm_clams(filename, ctl, atm);
6557
6558 /* Error... */
6559 else
6560 ERRMSG("Atmospheric data type not supported!");
6561
6562 /* Write info... */
6563 double mini, maxi;
6564 LOG(2, "Number of particles: %d", atm->np);
6565 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6566 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6567 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6568 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6569 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6570 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6571 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
6572 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6573 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
6574 for (int iq = 0; iq < ctl->nq; iq++) {
6575 char msg[5 * LEN];
6576 sprintf(msg, "Quantity %s range: %s ... %s %s",
6577 ctl->qnt_name[iq], ctl->qnt_format[iq],
6578 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6579 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6580 LOG(2, msg, mini, maxi);
6581 }
6582}
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:11260
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:11075
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:11207
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:11157
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:11418
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.
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 7, 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 6586 of file mptrac.c.

6589 {
6590
6591 /* Set timer... */
6592 SELECT_TIMER("WRITE_MET", "OUTPUT");
6593
6594 /* Write info... */
6595 LOG(1, "Write meteo data: %s", filename);
6596
6597 /* Check compression flags... */
6598#ifndef ZFP
6599 if (ctl->met_type == 3)
6600 ERRMSG("MPTRAC was compiled without ZFP compression!");
6601#endif
6602#ifndef ZSTD
6603 if (ctl->met_type == 4)
6604 ERRMSG("MPTRAC was compiled without ZSTD compression!");
6605#endif
6606#ifndef CMS
6607 if (ctl->met_type == 5)
6608 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6609#endif
6610#ifndef SZ3
6611 if (ctl->met_type == 7)
6612 ERRMSG("MPTRAC was compiled without SZ3 compression!");
6613#endif
6614
6615 /* Write netCDF data... */
6616 if (ctl->met_type == 0)
6617 write_met_nc(filename, ctl, met);
6618
6619 /* Write binary data... */
6620 else if (ctl->met_type >= 1 && ctl->met_type <= 7)
6621 write_met_bin(filename, ctl, met);
6622
6623 /* Not implemented... */
6624 else
6625 ERRMSG("MET_TYPE not implemented!");
6626}
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:12497
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:12264
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 6630 of file mptrac.c.

6636 {
6637
6638 char ext[10], filename[2 * LEN];
6639
6640 double r;
6641
6642 int year, mon, day, hour, min, sec;
6643
6644 /* Get time... */
6645 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
6646
6647 /* Update host... */
6648 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
6649 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
6650 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
6651 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
6652 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
6653 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
6654 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
6655
6656 /* Write atmospheric data... */
6657 if (ctl->atm_basename[0] != '-' &&
6658 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
6659 if (ctl->atm_type_out == 0)
6660 sprintf(ext, "tab");
6661 else if (ctl->atm_type_out == 1)
6662 sprintf(ext, "bin");
6663 else if (ctl->atm_type_out == 2)
6664 sprintf(ext, "nc");
6665 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6666 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
6667 mptrac_write_atm(filename, ctl, atm, t);
6668 }
6669
6670 /* Write gridded data... */
6671 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
6672 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6673 dirname, ctl->grid_basename, year, mon, day, hour, min,
6674 ctl->grid_type == 0 ? "tab" : "nc");
6675 write_grid(filename, ctl, met0, met1, atm, t);
6676 }
6677
6678 /* Write CSI data... */
6679 if (ctl->csi_basename[0] != '-') {
6680 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
6681 write_csi(filename, ctl, atm, t);
6682 }
6683
6684 /* Write ensemble data... */
6685 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
6686 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
6687 dirname, ctl->ens_basename, year, mon, day, hour, min);
6688 write_ens(filename, ctl, atm, t);
6689 }
6690
6691 /* Write profile data... */
6692 if (ctl->prof_basename[0] != '-') {
6693 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
6694 write_prof(filename, ctl, met0, met1, atm, t);
6695 }
6696
6697 /* Write sample data... */
6698 if (ctl->sample_basename[0] != '-') {
6699 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
6700 write_sample(filename, ctl, met0, met1, atm, t);
6701 }
6702
6703 /* Write station data... */
6704 if (ctl->stat_basename[0] != '-') {
6705 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
6706 write_station(filename, ctl, atm, t);
6707 }
6708
6709 /* Write VTK data... */
6710 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
6711 static int nvtk;
6712 if (t == ctl->t_start)
6713 nvtk = 0;
6714 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
6715 write_vtk(filename, ctl, atm, t);
6716 }
6717}
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:6526
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:11742
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:12720
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:6470
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:13109
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:13195
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:12947
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:11839
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:11467
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 6721 of file mptrac.c.

6724 {
6725
6726 /* Check water vapor volume mixing ratio... */
6727 const double h2o_help = MAX(h2o, 0.1e-6);
6728
6729 /* Calculate T_NAT... */
6730 const double p_hno3 = hno3 * p / 1.333224;
6731 const double p_h2o = h2o_help * p / 1.333224;
6732 const double a = 0.009179 - 0.00088 * log10(p_h2o);
6733 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
6734 const double c = -11397.0 / a;
6735 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
6736 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
6737 if (x2 > 0)
6738 tnat = x2;
6739
6740 return tnat;
6741}

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

6750 {
6751
6752 /* Get pressure range... */
6753 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
6754 const double p0 = pbl;
6755
6756 /* Get weighting factor... */
6757 if (atm->p[ip] > p0)
6758 return 1;
6759 else if (atm->p[ip] < p1)
6760 return 0;
6761 else
6762 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
6763}

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

6770 {
6771
6772 /* Open file... */
6773 FILE *in;
6774 if (!(in = fopen(filename, "r"))) {
6775 WARN("Cannot open file!");
6776 return 0;
6777 }
6778
6779 /* Read line... */
6780 char line[LEN];
6781 while (fgets(line, LEN, in)) {
6782
6783 /* Read data... */
6784 char *tok;
6785 TOK(line, tok, "%lg", atm->time[atm->np]);
6786 TOK(NULL, tok, "%lg", atm->p[atm->np]);
6787 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
6788 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
6789 for (int iq = 0; iq < ctl->nq; iq++)
6790 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
6791
6792 /* Convert altitude to pressure... */
6793 atm->p[atm->np] = P(atm->p[atm->np]);
6794
6795 /* Increment data point counter... */
6796 if ((++atm->np) > NP)
6797 ERRMSG("Too many data points!");
6798 }
6799
6800 /* Close file... */
6801 fclose(in);
6802
6803 /* Return success... */
6804 return 1;
6805}
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1870

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

6812 {
6813
6814 /* Open file... */
6815 FILE *in;
6816 if (!(in = fopen(filename, "r")))
6817 return 0;
6818
6819 /* Check version of binary data... */
6820 int version;
6821 FREAD(&version, int,
6822 1,
6823 in);
6824 if (version != 100)
6825 ERRMSG("Wrong version of binary data!");
6826
6827 /* Read data... */
6828 FREAD(&atm->np, int,
6829 1,
6830 in);
6831 FREAD(atm->time, double,
6832 (size_t) atm->np,
6833 in);
6834 FREAD(atm->p, double,
6835 (size_t) atm->np,
6836 in);
6837 FREAD(atm->lon, double,
6838 (size_t) atm->np,
6839 in);
6840 FREAD(atm->lat, double,
6841 (size_t) atm->np,
6842 in);
6843 for (int iq = 0; iq < ctl->nq; iq++)
6844 FREAD(atm->q[iq], double,
6845 (size_t) atm->np,
6846 in);
6847
6848 /* Read final flag... */
6849 int final;
6850 FREAD(&final, int,
6851 1,
6852 in);
6853 if (final != 999)
6854 ERRMSG("Error while reading binary data!");
6855
6856 /* Close file... */
6857 fclose(in);
6858
6859 /* Return success... */
6860 return 1;
6861}

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

6868 {
6869
6870 int ncid, varid;
6871
6872 /* Open file... */
6873 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6874 return 0;
6875
6876 /* Get dimensions... */
6877 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
6878
6879 /* Get time... */
6880 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
6881 NC(nc_get_var_double(ncid, varid, atm->time));
6882 } else {
6883 WARN("TIME_INIT not found use time instead!");
6884 double time_init;
6885 NC_GET_DOUBLE("time", &time_init, 1);
6886 for (int ip = 0; ip < atm->np; ip++) {
6887 atm->time[ip] = time_init;
6888 }
6889 }
6890
6891 /* Read zeta coordinate, pressure is optional... */
6892 if (ctl->advect_vert_coord == 1) {
6893 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
6894 NC_GET_DOUBLE("PRESS", atm->p, 0);
6895 }
6896
6897 /* Read pressure, zeta coordinate is optional... */
6898 else {
6899 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
6900 NC(nc_get_var_double(ncid, varid, atm->p));
6901 } else {
6902 WARN("PRESS_INIT not found use PRESS instead!");
6903 nc_inq_varid(ncid, "PRESS", &varid);
6904 NC(nc_get_var_double(ncid, varid, atm->p));
6905 }
6906 }
6907
6908 /* Read further quantities if requested... */
6909 for (int iq = 0; iq < ctl->nq; iq++)
6910 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6911
6912 /* Read longitude and latitude... */
6913 NC_GET_DOUBLE("LON", atm->lon, 1);
6914 NC_GET_DOUBLE("LAT", atm->lat, 1);
6915
6916 /* Close file... */
6917 NC(nc_close(ncid));
6918
6919 /* Return success... */
6920 return 1;
6921}
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1204
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1263
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1293

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

6928 {
6929
6930 int ncid, varid;
6931
6932 /* Open file... */
6933 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6934 return 0;
6935
6936 /* Get dimensions... */
6937 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
6938
6939 /* Read geolocations... */
6940 NC_GET_DOUBLE("time", atm->time, 1);
6941 NC_GET_DOUBLE("press", atm->p, 1);
6942 NC_GET_DOUBLE("lon", atm->lon, 1);
6943 NC_GET_DOUBLE("lat", atm->lat, 1);
6944
6945 /* Read variables... */
6946 for (int iq = 0; iq < ctl->nq; iq++)
6947 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6948
6949 /* Close file... */
6950 NC(nc_close(ncid));
6951
6952 /* Return success... */
6953 return 1;
6954}

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

6960 {
6961
6962 int ncid, varid;
6963
6964 /* Write info... */
6965 LOG(1, "Read photolysis rates: %s", filename);
6966
6967 /* Open netCDF file... */
6968 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6969 WARN("Photolysis rate data are missing!");
6970 return;
6971 }
6972
6973 /* Read pressure data... */
6974 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
6975 NC_GET_DOUBLE("press", photo->p, 1);
6976 if (photo->p[0] < photo->p[1])
6977 ERRMSG("Pressure data are not descending!");
6978
6979 /* Read total column ozone data... */
6980 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
6981 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
6982 if (photo->o3c[0] > photo->o3c[1])
6983 ERRMSG("Total column ozone data are not ascending!");
6984
6985 /* Read solar zenith angle data... */
6986 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
6987 NC_GET_DOUBLE("sza", photo->sza, 1);
6988 if (photo->sza[0] > photo->sza[1])
6989 ERRMSG("Solar zenith angle data are not ascending!");
6990
6991 /* Read data... */
6992 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
6993 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
6994 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
6995 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
6996 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
6997 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
6998 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
6999 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
7000 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
7001
7002 /* Close netCDF file... */
7003 NC(nc_close(ncid));
7004
7005 /* Write info... */
7006 LOG(2, "Number of pressure levels: %d", photo->np);
7007 LOG(2, "Altitude levels: %g, %g ... %g km",
7008 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
7009 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7010 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
7011 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
7012 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
7013 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
7014 RAD2DEG(photo->sza[photo->nsza - 1]));
7015 LOG(2, "Number of total column ozone values: %d", photo->no3c);
7016 LOG(2, "Total column ozone: %g, %g ... %g DU",
7017 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
7018 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
7019 photo->n2o[0][0][0], photo->n2o[1][0][0],
7020 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7021 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
7022 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
7023 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7024 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
7025 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
7026 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7027 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
7028 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
7029 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7030 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
7031 photo->o2[0][0][0], photo->o2[1][0][0],
7032 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7033 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
7034 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
7035 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7036 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
7037 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
7038 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7039 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
7040 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
7041 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7042 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
7043 photo->h2o[0][0][0], photo->h2o[1][0][0],
7044 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7045}
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:7049
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:395
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:390
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:400
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3364
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3361
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3370
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3373
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3367
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 7049 of file mptrac.c.

7053 {
7054
7055 /* Allocate... */
7056 double *help;
7057 ALLOC(help, double,
7058 photo->np * photo->nsza * photo->no3c);
7059
7060 /* Read varible... */
7061 int varid;
7062 NC_GET_DOUBLE(varname, help, 1);
7063
7064 /* Copy data... */
7065 for (int ip = 0; ip < photo->np; ip++)
7066 for (int is = 0; is < photo->nsza; is++)
7067 for (int io = 0; io < photo->no3c; io++)
7068 var[ip][is][io] =
7069 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
7070
7071 /* Free... */
7072 free(help);
7073}

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

7079 {
7080
7081 /* Write info... */
7082 LOG(1, "Read climatological time series: %s", filename);
7083
7084 /* Open file... */
7085 FILE *in;
7086 if (!(in = fopen(filename, "r"))) {
7087 WARN("Cannot open file!");
7088 return 0;
7089 }
7090
7091 /* Read data... */
7092 char line[LEN];
7093 int nh = 0;
7094 while (fgets(line, LEN, in))
7095 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
7096
7097 /* Convert years to seconds... */
7098 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
7099
7100 /* Check data... */
7101 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
7102 ERRMSG("Time series must be ascending!");
7103
7104 /* Count time steps... */
7105 if ((++nh) >= CTS)
7106 ERRMSG("Too many data points!");
7107 }
7108
7109 /* Close file... */
7110 fclose(in);
7111
7112 /* Check number of data points... */
7113 ts->ntime = nh;
7114 if (nh < 2)
7115 ERRMSG("Not enough data points!");
7116
7117 /* Write info... */
7118 LOG(2, "Number of time steps: %d", ts->ntime);
7119 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
7120 ts->time[nh - 1]);
7121 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
7122 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
7123 (size_t) nh));
7124
7125 /* Exit success... */
7126 return 1;
7127}
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:410

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

7134 {
7135
7136 int ncid, varid, it, iy, iz, iz2, nt;
7137
7138 double *help, varmin = 1e99, varmax = -1e99;
7139
7140 /* Write info... */
7141 LOG(1, "Read %s data: %s", varname, filename);
7142
7143 /* Open netCDF file... */
7144 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7145 WARN("%s climatology data are missing!", varname);
7146 return;
7147 }
7148
7149 /* Read pressure data... */
7150 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
7151 NC_GET_DOUBLE("press", zm->p, 1);
7152 if (zm->p[0] < zm->p[1])
7153 ERRMSG("Pressure data are not descending!");
7154
7155 /* Read latitudes... */
7156 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
7157 NC_GET_DOUBLE("lat", zm->lat, 1);
7158 if (zm->lat[0] > zm->lat[1])
7159 ERRMSG("Latitude data are not ascending!");
7160
7161 /* Set time data (for monthly means)... */
7162 zm->ntime = 12;
7163 zm->time[0] = 1209600.00;
7164 zm->time[1] = 3888000.00;
7165 zm->time[2] = 6393600.00;
7166 zm->time[3] = 9072000.00;
7167 zm->time[4] = 11664000.00;
7168 zm->time[5] = 14342400.00;
7169 zm->time[6] = 16934400.00;
7170 zm->time[7] = 19612800.00;
7171 zm->time[8] = 22291200.00;
7172 zm->time[9] = 24883200.00;
7173 zm->time[10] = 27561600.00;
7174 zm->time[11] = 30153600.00;
7175
7176 /* Check number of timesteps... */
7177 NC_INQ_DIM("time", &nt, 12, 12, 1);
7178
7179 /* Read data... */
7180 ALLOC(help, double,
7181 zm->nlat * zm->np * zm->ntime);
7182 NC_GET_DOUBLE(varname, help, 1);
7183 for (it = 0; it < zm->ntime; it++)
7184 for (iz = 0; iz < zm->np; iz++)
7185 for (iy = 0; iy < zm->nlat; iy++)
7186 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
7187 free(help);
7188
7189 /* Fix data gaps... */
7190 for (it = 0; it < zm->ntime; it++)
7191 for (iy = 0; iy < zm->nlat; iy++)
7192 for (iz = 0; iz < zm->np; iz++) {
7193 if (zm->vmr[it][iz][iy] < 0) {
7194 for (iz2 = 0; iz2 < zm->np; iz2++)
7195 if (zm->vmr[it][iz2][iy] >= 0) {
7196 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7197 break;
7198 }
7199 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
7200 if (zm->vmr[it][iz2][iy] >= 0) {
7201 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7202 break;
7203 }
7204 }
7205 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
7206 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
7207 }
7208
7209 /* Close netCDF file... */
7210 NC(nc_close(ncid));
7211
7212 /* Write info... */
7213 LOG(2, "Number of time steps: %d", zm->ntime);
7214 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
7215 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
7216 LOG(2, "Number of pressure levels: %d", zm->np);
7217 LOG(2, "Altitude levels: %g, %g ... %g km",
7218 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
7219 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
7220 zm->p[1], zm->p[zm->np - 1]);
7221 LOG(2, "Number of latitudes: %d", zm->nlat);
7222 LOG(2, "Latitudes: %g, %g ... %g deg",
7223 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
7224 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
7225 varmax);
7226}
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:385

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

7234 {
7235
7236 /* Write info... */
7237 LOG(1, "Read kernel function: %s", filename);
7238
7239 /* Open file... */
7240 FILE *in;
7241 if (!(in = fopen(filename, "r")))
7242 ERRMSG("Cannot open file!");
7243
7244 /* Read data... */
7245 char line[LEN];
7246 int n = 0;
7247 while (fgets(line, LEN, in))
7248 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
7249 if (n > 0 && kz[n] < kz[n - 1])
7250 ERRMSG("Height levels must be ascending!");
7251 if ((++n) >= EP)
7252 ERRMSG("Too many height levels!");
7253 }
7254
7255 /* Close file... */
7256 fclose(in);
7257
7258 /* Check number of data points... */
7259 *nk = n;
7260 if (n < 2)
7261 ERRMSG("Not enough height levels!");
7262
7263 /* Normalize kernel function... */
7264 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
7265 for (int iz = 0; iz < n; iz++)
7266 kw[iz] /= kmax;
7267}

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

7274 {
7275
7276 FILE *in;
7277
7278 double r;
7279
7280 int year, mon, day, hour, min, sec;
7281
7282 /* Set timer... */
7283 SELECT_TIMER("READ_MET_BIN", "INPUT");
7284
7285 /* Open file... */
7286 if (!(in = fopen(filename, "r"))) {
7287 WARN("Cannot open file!");
7288 return 0;
7289 }
7290
7291 /* Check type of binary data... */
7292 int met_type;
7293 FREAD(&met_type, int,
7294 1,
7295 in);
7296 if (met_type != ctl->met_type)
7297 ERRMSG("Wrong MET_TYPE of binary data!");
7298
7299 /* Check version of binary data... */
7300 int version;
7301 FREAD(&version, int,
7302 1,
7303 in);
7304 if (version != 103)
7305 ERRMSG("Wrong version of binary data!");
7306
7307 /* Read time... */
7308 FREAD(&met->time, double,
7309 1,
7310 in);
7311 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7312 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7313 met->time, year, mon, day, hour, min);
7314 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7315 || day < 1 || day > 31 || hour < 0 || hour > 23)
7316 ERRMSG("Error while reading time!");
7317
7318 /* Read dimensions... */
7319 FREAD(&met->nx, int,
7320 1,
7321 in);
7322 LOG(2, "Number of longitudes: %d", met->nx);
7323 if (met->nx < 2 || met->nx > EX)
7324 ERRMSG("Number of longitudes out of range!");
7325
7326 FREAD(&met->ny, int,
7327 1,
7328 in);
7329 LOG(2, "Number of latitudes: %d", met->ny);
7330 if (met->ny < 2 || met->ny > EY)
7331 ERRMSG("Number of latitudes out of range!");
7332
7333 FREAD(&met->np, int,
7334 1,
7335 in);
7336 LOG(2, "Number of levels: %d", met->np);
7337 if (met->np < 2 || met->np > EP)
7338 ERRMSG("Number of levels out of range!");
7339
7340 /* Read grid... */
7341 FREAD(met->lon, double,
7342 (size_t) met->nx,
7343 in);
7344 LOG(2, "Longitudes: %g, %g ... %g deg",
7345 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7346
7347 FREAD(met->lat, double,
7348 (size_t) met->ny,
7349 in);
7350 LOG(2, "Latitudes: %g, %g ... %g deg",
7351 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7352
7353 FREAD(met->p, double,
7354 (size_t) met->np,
7355 in);
7356 LOG(2, "Altitude levels: %g, %g ... %g km",
7357 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7358 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7359 met->p[0], met->p[1], met->p[met->np - 1]);
7360
7361 /* Read surface data... */
7362 read_met_bin_2d(in, met, met->ps, "PS");
7363 read_met_bin_2d(in, met, met->ts, "TS");
7364 read_met_bin_2d(in, met, met->zs, "ZS");
7365 read_met_bin_2d(in, met, met->us, "US");
7366 read_met_bin_2d(in, met, met->vs, "VS");
7367 read_met_bin_2d(in, met, met->ess, "ESS");
7368 read_met_bin_2d(in, met, met->nss, "NSS");
7369 read_met_bin_2d(in, met, met->shf, "SHF");
7370 read_met_bin_2d(in, met, met->lsm, "LSM");
7371 read_met_bin_2d(in, met, met->sst, "SST");
7372 read_met_bin_2d(in, met, met->pbl, "PBL");
7373 read_met_bin_2d(in, met, met->pt, "PT");
7374 read_met_bin_2d(in, met, met->tt, "TT");
7375 read_met_bin_2d(in, met, met->zt, "ZT");
7376 read_met_bin_2d(in, met, met->h2ot, "H2OT");
7377 read_met_bin_2d(in, met, met->pct, "PCT");
7378 read_met_bin_2d(in, met, met->pcb, "PCB");
7379 read_met_bin_2d(in, met, met->cl, "CL");
7380 read_met_bin_2d(in, met, met->plcl, "PLCL");
7381 read_met_bin_2d(in, met, met->plfc, "PLFC");
7382 read_met_bin_2d(in, met, met->pel, "PEL");
7383 read_met_bin_2d(in, met, met->cape, "CAPE");
7384 read_met_bin_2d(in, met, met->cin, "CIN");
7385 read_met_bin_2d(in, met, met->o3c, "O3C");
7386
7387 /* Read level data... */
7388 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
7389 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
7390 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
7391 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
7392 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
7393 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
7394 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
7395 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
7396 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
7397 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
7398 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
7399 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
7400 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
7401
7402 /* Read final flag... */
7403 int final;
7404 FREAD(&final, int,
7405 1,
7406 in);
7407 if (final != 999)
7408 ERRMSG("Error while reading binary data!");
7409
7410 /* Close file... */
7411 fclose(in);
7412
7413 /* Return success... */
7414 return 1;
7415}
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:7419
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:7448
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:340
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3573
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3561
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3633
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3603
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3597
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3579
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3555
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3630
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3543
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3642
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3537
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3549
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3582
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3594
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3600
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3588
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3570
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3564
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3546
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3558
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3636
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3576
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3621
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3585
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3552
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3591
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3639
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 7419 of file mptrac.c.

7423 {
7424
7425 float *help;
7426
7427 /* Allocate... */
7428 ALLOC(help, float,
7429 EX * EY);
7430
7431 /* Read uncompressed... */
7432 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
7433 FREAD(help, float,
7434 (size_t) (met->nx * met->ny),
7435 in);
7436
7437 /* Copy data... */
7438 for (int ix = 0; ix < met->nx; ix++)
7439 for (int iy = 0; iy < met->ny; iy++)
7440 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
7441
7442 /* Free... */
7443 free(help);
7444}
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:476

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

7455 {
7456
7457 float *help;
7458
7459 /* Allocate... */
7460 ALLOC(help, float,
7461 EX * EY * EP);
7462
7463 /* Read uncompressed data... */
7464 if (ctl->met_type == 1) {
7465 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
7466 FREAD(help, float,
7467 (size_t) (met->nx * met->ny * met->np),
7468 in);
7469 }
7470
7471 /* Read packed data... */
7472 else if (ctl->met_type == 2)
7473 compress_pck(varname, help, (size_t) (met->ny * met->nx),
7474 (size_t) met->np, 1, in);
7475
7476 /* Read ZFP data... */
7477 else if (ctl->met_type == 3) {
7478#ifdef ZFP
7479 int precision;
7480 FREAD(&precision, int,
7481 1,
7482 in);
7483
7484 double tolerance;
7485 FREAD(&tolerance, double,
7486 1,
7487 in);
7488
7489 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
7490 tolerance, 1, in);
7491#else
7492 ERRMSG("MPTRAC was compiled without ZFP compression!");
7493#endif
7494 }
7495
7496 /* Read zstd data... */
7497 else if (ctl->met_type == 4) {
7498#ifdef ZSTD
7499 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
7500 ctl->met_zstd_level, in);
7501#else
7502 ERRMSG("MPTRAC was compiled without ZSTD compression!");
7503#endif
7504 }
7505
7506 /* Read cmultiscale data... */
7507 else if (ctl->met_type == 5) {
7508#ifdef CMS
7509 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
7510 (size_t) met->np, met->p, 1, in);
7511#else
7512 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
7513#endif
7514 }
7515
7516 /* Read SZ3 data... */
7517 else if (ctl->met_type == 7) {
7518#ifdef SZ3
7519 int precision;
7520 FREAD(&precision, int,
7521 1,
7522 in);
7523
7524 double tolerance;
7525 FREAD(&tolerance, double,
7526 1,
7527 in);
7528
7529 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
7530 tolerance, 1, in);
7531#else
7532 ERRMSG("MPTRAC was compiled without sz3 compression!");
7533#endif
7534 }
7535
7536 /* Copy data... */
7537#pragma omp parallel for default(shared) collapse(2)
7538 for (int ix = 0; ix < met->nx; ix++)
7539 for (int iy = 0; iy < met->ny; iy++)
7540 for (int ip = 0; ip < met->np; ip++) {
7541 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7542 if (var[ix][iy][ip] < bound_min)
7543 var[ix][iy][ip] = bound_min;
7544 else if (var[ix][iy][ip] > bound_max)
7545 var[ix][iy][ip] = bound_max;
7546 }
7547
7548 /* Free... */
7549 free(help);
7550}
void compress_pck(const char *varname, float *array, const size_t nxy, const size_t nz, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats.
Definition: mptrac.c:680
void compress_zstd(const char *varname, float *array, const size_t n, const int decompress, const int level, FILE *inout)
Compresses or decompresses a float array using Zstandard (ZSTD).
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 *inout)
Compresses or decompresses a 3-D meteorological field using cmultiscale.
void compress_zfp(const char *varname, float *array, const int nx, const int ny, const int nz, const int precision, const double tolerance, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
void compress_sz3(const char *varname, float *array, const int nx, const int ny, const int nz, const int precision, const double tolerance, const int decompress, FILE *inout)
Compresses or decompresses a 3-D float array using the SZ3 library.
int met_zstd_level
ZSTD compression level (from -5 to 22).
Definition: mptrac.h:2563
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 7554 of file mptrac.c.

7557 {
7558
7559 /* Check parameters... */
7560 if (ctl->met_cape != 1)
7561 return;
7562
7563 /* Set timer... */
7564 SELECT_TIMER("READ_MET_CAPE", "METPROC");
7565 LOG(2, "Calculate CAPE...");
7566
7567 /* Vertical spacing (about 100 m)... */
7568 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
7569
7570 /* Loop over columns... */
7571#pragma omp parallel for default(shared) collapse(2)
7572 for (int ix = 0; ix < met->nx; ix++)
7573 for (int iy = 0; iy < met->ny; iy++) {
7574
7575 /* Get potential temperature and water vapor at lowest 50 hPa... */
7576 int n = 0;
7577 double h2o = 0, t, theta = 0;
7578 double pbot = MIN(met->ps[ix][iy], met->p[0]);
7579 double ptop = pbot - 50.;
7580 for (int ip = 0; ip < met->np; ip++) {
7581 if (met->p[ip] <= pbot) {
7582 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
7583 h2o += met->h2o[ix][iy][ip];
7584 n++;
7585 }
7586 if (met->p[ip] < ptop && n > 0)
7587 break;
7588 }
7589 theta /= n;
7590 h2o /= n;
7591
7592 /* Cannot compute anything if water vapor is missing... */
7593 met->plcl[ix][iy] = NAN;
7594 met->plfc[ix][iy] = NAN;
7595 met->pel[ix][iy] = NAN;
7596 met->cape[ix][iy] = NAN;
7597 met->cin[ix][iy] = NAN;
7598 if (h2o <= 0)
7599 continue;
7600
7601 /* Find lifted condensation level (LCL)... */
7602 ptop = P(20.);
7603 pbot = met->ps[ix][iy];
7604 do {
7605 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
7606 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
7607 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
7608 ptop = met->plcl[ix][iy];
7609 else
7610 pbot = met->plcl[ix][iy];
7611 } while (pbot - ptop > 0.1);
7612
7613 /* Calculate CIN up to LCL... */
7615 double dcape, dz, h2o_env, t_env;
7616 double p = met->ps[ix][iy];
7617 met->cape[ix][iy] = met->cin[ix][iy] = 0;
7618 do {
7619 dz = dz0 * TVIRT(t, h2o);
7620 p /= pfac;
7621 t = theta / pow(1000. / p, 0.286);
7622 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7623 &t_env, ci, cw, 1);
7624 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7625 &h2o_env, ci, cw, 0);
7626 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7627 TVIRT(t_env, h2o_env) * dz;
7628 if (dcape < 0)
7629 met->cin[ix][iy] += fabsf((float) dcape);
7630 } while (p > met->plcl[ix][iy]);
7631
7632 /* Calculate level of free convection (LFC), equilibrium level (EL),
7633 and convective available potential energy (CAPE)... */
7634 dcape = 0;
7635 p = met->plcl[ix][iy];
7636 t = theta / pow(1000. / p, 0.286);
7637 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
7638 do {
7639 dz = dz0 * TVIRT(t, h2o);
7640 p /= pfac;
7641 t -= lapse_rate(t, h2o) * dz;
7642 double psat = PSAT(t);
7643 h2o = psat / (p - (1. - EPS) * psat);
7644 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7645 &t_env, ci, cw, 1);
7646 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7647 &h2o_env, ci, cw, 0);
7648 double dcape_old = dcape;
7649 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7650 TVIRT(t_env, h2o_env) * dz;
7651 if (dcape > 0) {
7652 met->cape[ix][iy] += (float) dcape;
7653 if (!isfinite(met->plfc[ix][iy]))
7654 met->plfc[ix][iy] = (float) p;
7655 } else if (dcape_old > 0)
7656 met->pel[ix][iy] = (float) p;
7657 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
7658 met->cin[ix][iy] += fabsf((float) dcape);
7659 } while (p > ptop);
7660
7661 /* Check results... */
7662 if (!isfinite(met->plfc[ix][iy]))
7663 met->cin[ix][iy] = NAN;
7664 }
7665}
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:204
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 7669 of file mptrac.c.

7670 {
7671
7672 /* Set timer... */
7673 SELECT_TIMER("READ_MET_CLOUD", "METPROC");
7674 LOG(2, "Calculate cloud data...");
7675
7676 /* Thresholds for cloud detection... */
7677 const double ccmin = 0.01, cwmin = 1e-6;
7678
7679 /* Loop over columns... */
7680#pragma omp parallel for default(shared) collapse(2)
7681 for (int ix = 0; ix < met->nx; ix++)
7682 for (int iy = 0; iy < met->ny; iy++) {
7683
7684 /* Init... */
7685 met->pct[ix][iy] = NAN;
7686 met->pcb[ix][iy] = NAN;
7687 met->cl[ix][iy] = 0;
7688
7689 /* Loop over pressure levels... */
7690 for (int ip = 0; ip < met->np - 1; ip++) {
7691
7692 /* Check pressure... */
7693 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
7694 continue;
7695
7696 /* Check ice water and liquid water content... */
7697 if (met->cc[ix][iy][ip] > ccmin
7698 && (met->lwc[ix][iy][ip] > cwmin
7699 || met->rwc[ix][iy][ip] > cwmin
7700 || met->iwc[ix][iy][ip] > cwmin
7701 || met->swc[ix][iy][ip] > cwmin)) {
7702
7703 /* Get cloud top pressure ... */
7704 met->pct[ix][iy]
7705 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
7706
7707 /* Get cloud bottom pressure ... */
7708 if (!isfinite(met->pcb[ix][iy]))
7709 met->pcb[ix][iy]
7710 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
7711 }
7712
7713 /* Get cloud water... */
7714 met->cl[ix][iy] += (float)
7715 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
7716 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
7717 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
7718 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
7719 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
7720 }
7721 }
7722}

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

7728 {
7729
7730 met_t *help;
7731
7732 /* Check parameters... */
7733 if (ctl->met_detrend <= 0)
7734 return;
7735
7736 /* Set timer... */
7737 SELECT_TIMER("READ_MET_DETREND", "METPROC");
7738 LOG(2, "Detrend meteo data...");
7739
7740 /* Allocate... */
7741 ALLOC(help, met_t, 1);
7742
7743 /* Calculate standard deviation... */
7744 const double sigma = ctl->met_detrend / 2.355;
7745 const double tssq = 2. * SQR(sigma);
7746
7747 /* Calculate box size in latitude... */
7748 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
7749 sy = MIN(MAX(1, sy), met->ny / 2);
7750
7751 /* Calculate background... */
7752#pragma omp parallel for default(shared) collapse(2)
7753 for (int ix = 0; ix < met->nx; ix++) {
7754 for (int iy = 0; iy < met->ny; iy++) {
7755
7756 /* Calculate Cartesian coordinates... */
7757 double x0[3];
7758 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
7759
7760 /* Calculate box size in longitude... */
7761 int sx =
7762 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
7763 fabs(met->lon[1] - met->lon[0]));
7764 sx = MIN(MAX(1, sx), met->nx / 2);
7765
7766 /* Init... */
7767 float wsum = 0;
7768 for (int ip = 0; ip < met->np; ip++) {
7769 help->t[ix][iy][ip] = 0;
7770 help->u[ix][iy][ip] = 0;
7771 help->v[ix][iy][ip] = 0;
7772 help->w[ix][iy][ip] = 0;
7773 }
7774
7775 /* Loop over neighboring grid points... */
7776 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
7777 int ix3 = ix2;
7778 if (ix3 < 0)
7779 ix3 += met->nx;
7780 else if (ix3 >= met->nx)
7781 ix3 -= met->nx;
7782 for (int iy2 = MAX(iy - sy, 0);
7783 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
7784
7785 /* Calculate Cartesian coordinates... */
7786 double x1[3];
7787 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
7788
7789 /* Calculate weighting factor... */
7790 const float w = (float) exp(-DIST2(x0, x1) / tssq);
7791
7792 /* Add data... */
7793 wsum += w;
7794 for (int ip = 0; ip < met->np; ip++) {
7795 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
7796 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
7797 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
7798 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
7799 }
7800 }
7801 }
7802
7803 /* Normalize... */
7804 for (int ip = 0; ip < met->np; ip++) {
7805 help->t[ix][iy][ip] /= wsum;
7806 help->u[ix][iy][ip] /= wsum;
7807 help->v[ix][iy][ip] /= wsum;
7808 help->w[ix][iy][ip] /= wsum;
7809 }
7810 }
7811 }
7812
7813 /* Subtract background... */
7814#pragma omp parallel for default(shared) collapse(3)
7815 for (int ix = 0; ix < met->nx; ix++)
7816 for (int iy = 0; iy < met->ny; iy++)
7817 for (int ip = 0; ip < met->np; ip++) {
7818 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
7819 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
7820 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
7821 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
7822 }
7823
7824 /* Free... */
7825 free(help);
7826}
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:1674
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:720
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 7830 of file mptrac.c.

7831 {
7832
7833 /* Set timer... */
7834 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC");
7835 LOG(2, "Extrapolate meteo data...");
7836
7837 /* Loop over columns... */
7838#pragma omp parallel for default(shared) collapse(2)
7839 for (int ix = 0; ix < met->nx; ix++)
7840 for (int iy = 0; iy < met->ny; iy++) {
7841
7842 /* Find lowest valid data point... */
7843 int ip0;
7844 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
7845 if (!isfinite(met->t[ix][iy][ip0])
7846 || !isfinite(met->u[ix][iy][ip0])
7847 || !isfinite(met->v[ix][iy][ip0])
7848 || !isfinite(met->w[ix][iy][ip0]))
7849 break;
7850
7851 /* Extrapolate... */
7852 for (int ip = ip0; ip >= 0; ip--) {
7853 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
7854 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
7855 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
7856 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
7857 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
7858 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
7859 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
7860 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
7861 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
7862 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
7863 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
7864 }
7865 }
7866}

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

7872 {
7873
7874 float *help;
7875
7876 double logp[EP];
7877
7878 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
7879
7880 /* Set timer... */
7881 SELECT_TIMER("READ_MET_GEOPOT", "METPROC");
7882 LOG(2, "Calculate geopotential heights...");
7883
7884 /* Allocate... */
7885 ALLOC(help, float,
7886 EX * EY * EP);
7887
7888 /* Calculate log pressure... */
7889#pragma omp parallel for default(shared)
7890 for (int ip = 0; ip < met->np; ip++)
7891 logp[ip] = log(met->p[ip]);
7892
7893 /* Apply hydrostatic equation to calculate geopotential heights... */
7894#pragma omp parallel for default(shared) collapse(2)
7895 for (int ix = 0; ix < met->nx; ix++)
7896 for (int iy = 0; iy < met->ny; iy++) {
7897
7898 /* Get surface height and pressure... */
7899 const double zs = met->zs[ix][iy];
7900 const double lnps = log(met->ps[ix][iy]);
7901
7902 /* Get temperature and water vapor at the surface... */
7903 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
7904 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
7905 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
7906 const double h2os =
7907 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
7908 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
7909
7910 /* Upper part of profile... */
7911 met->z[ix][iy][ip0 + 1]
7912 = (float) (zs +
7913 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
7914 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
7915 for (int ip = ip0 + 2; ip < met->np; ip++)
7916 met->z[ix][iy][ip]
7917 = (float) (met->z[ix][iy][ip - 1] +
7918 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
7919 met->h2o[ix][iy][ip - 1], logp[ip],
7920 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7921
7922 /* Lower part of profile... */
7923 met->z[ix][iy][ip0]
7924 = (float) (zs +
7925 ZDIFF(lnps, ts, h2os, logp[ip0],
7926 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
7927 for (int ip = ip0 - 1; ip >= 0; ip--)
7928 met->z[ix][iy][ip]
7929 = (float) (met->z[ix][iy][ip + 1] +
7930 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
7931 met->h2o[ix][iy][ip + 1], logp[ip],
7932 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7933 }
7934
7935 /* Check control parameters... */
7936 if (dx == 0 || dy == 0)
7937 return;
7938
7939 /* Default smoothing parameters... */
7940 if (dx < 0 || dy < 0) {
7941 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
7942 dx = 3;
7943 dy = 2;
7944 } else {
7945 dx = 6;
7946 dy = 4;
7947 }
7948 }
7949
7950 /* Calculate weights for smoothing... */
7951 float ws[dx + 1][dy + 1];
7952#pragma omp parallel for default(shared) collapse(2)
7953 for (int ix = 0; ix <= dx; ix++)
7954 for (int iy = 0; iy < dy; iy++)
7955 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
7956 * (1.0f - (float) iy / (float) dy);
7957
7958 /* Copy data... */
7959#pragma omp parallel for default(shared) collapse(3)
7960 for (int ix = 0; ix < met->nx; ix++)
7961 for (int iy = 0; iy < met->ny; iy++)
7962 for (int ip = 0; ip < met->np; ip++)
7963 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
7964
7965 /* Horizontal smoothing... */
7966#pragma omp parallel for default(shared) collapse(3)
7967 for (int ip = 0; ip < met->np; ip++)
7968 for (int ix = 0; ix < met->nx; ix++)
7969 for (int iy = 0; iy < met->ny; iy++) {
7970 float res = 0, wsum = 0;
7971 int iy0 = MAX(iy - dy + 1, 0);
7972 int iy1 = MIN(iy + dy - 1, met->ny - 1);
7973 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
7974 int ix3 = ix2;
7975 if (ix3 < 0)
7976 ix3 += met->nx;
7977 else if (ix3 >= met->nx)
7978 ix3 -= met->nx;
7979 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
7980 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
7981 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
7982 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
7983 wsum += w;
7984 }
7985 }
7986 if (wsum > 0)
7987 met->z[ix][iy][ip] = res / wsum;
7988 else
7989 met->z[ix][iy][ip] = NAN;
7990 }
7991
7992 /* Free... */
7993 free(help);
7994}
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1970
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 7998 of file mptrac.c.

8003 {
8004
8005 char levname[LEN], tstr[10];
8006
8007 double rtime = 0, r, r2;
8008
8009 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
8010 year, mon, day, hour, min, sec;
8011
8012 size_t dimlen;
8013
8014 /* Set timer... */
8015 SELECT_TIMER("READ_MET_NC_GRID", "INPUT");
8016 LOG(2, "Read meteo grid information...");
8017
8018 /* MPTRAC meteo files... */
8019 if (!ctl->met_clams) {
8020
8021 /* Get time from filename... */
8022 met->time = time_from_filename(filename, 16);
8023
8024 /* Check time information from data file... */
8025 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8026 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
8027 NC(nc_get_var_double(ncid, varid, &rtime));
8028 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
8029 WARN("Time information in meteo file does not match filename!");
8030 } else
8031 WARN("Time information in meteo file is missing!");
8032 }
8033
8034 /* CLaMS meteo files... */
8035 else {
8036
8037 /* Read time from file... */
8038 NC_GET_DOUBLE("time", &rtime, 0);
8039
8040 /* Get time from filename (considering the century)... */
8041 if (rtime < 0)
8042 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
8043 else
8044 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
8045 year = atoi(tstr);
8046 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
8047 mon = atoi(tstr);
8048 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
8049 day = atoi(tstr);
8050 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
8051 hour = atoi(tstr);
8052 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
8053 }
8054
8055 /* Check time... */
8056 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8057 || day < 1 || day > 31 || hour < 0 || hour > 23)
8058 ERRMSG("Cannot read time from filename!");
8059 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
8060 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8061 met->time, year2, mon2, day2, hour2, min2);
8062
8063 /* Get vertical dimension... */
8064 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
8065 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
8066 ERRMSG
8067 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
8068
8069 NC(nc_inq_varndims(ncid, varid, &ndims));
8070 NC(nc_inq_vardimid(ncid, varid, dimids));
8071
8072 if (ndims == 4) {
8073 NC(nc_inq_dim
8074 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
8075 } else if (ndims == 3) {
8076 NC(nc_inq_dim
8077 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
8078 } else
8079 ERRMSG("Cannot determine vertical dimension!")
8080 met->np = (int) dimlen;
8081
8082 LOG(2, "Number of levels: %d", met->np);
8083 if (met->np < 2 || met->np > EP)
8084 ERRMSG("Number of levels out of range!");
8085
8086 if (!ctl->dd) {
8087
8088 /* Get grid dimensions... */
8089 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
8090 LOG(2, "Number of longitudes: %d", met->nx);
8091
8092 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
8093 LOG(2, "Number of latitudes: %d", met->ny);
8094
8095 /* Read longitudes and latitudes... */
8096 NC_GET_DOUBLE("lon", met->lon, 1);
8097 LOG(2, "Longitudes: %g, %g ... %g deg",
8098 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
8099 NC_GET_DOUBLE("lat", met->lat, 1);
8100 LOG(2, "Latitudes: %g, %g ... %g deg",
8101 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
8102
8103 } else {
8104
8105 /* Use 'naive', i.e. equidistant lat-lon domain decomposition... */
8106 read_met_nc_grid_dd_naive(dd, ctl, met, ncid);
8107
8108 }
8109
8110 /* Read pressure levels... */
8111 if (ctl->met_np <= 0) {
8112 NC_GET_DOUBLE(levname, met->p, 1);
8113 for (int ip = 0; ip < met->np; ip++)
8114 met->p[ip] /= 100.;
8115 LOG(2, "Altitude levels: %g, %g ... %g km",
8116 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8117 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8118 met->p[0], met->p[1], met->p[met->np - 1]);
8119 }
8120
8121 /* Read hybrid levels... */
8122 if (strcasecmp(levname, "hybrid") == 0)
8123 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
8124
8125 /* Read model level coefficients from file... */
8126 if (ctl->met_vert_coord == 2) {
8127 NC_GET_DOUBLE("hyam", met->hyam, 1);
8128 NC_GET_DOUBLE("hybm", met->hybm, 1);
8129 }
8130
8131 /* Copy model level coefficients from control parameters... */
8132 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
8133 if (ctl->met_nlev <= 0)
8134 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
8135 for (int ip = 0; ip < ctl->met_nlev; ip++) {
8136 met->hyam[ip] = ctl->met_lev_hyam[ip];
8137 met->hybm[ip] = ctl->met_lev_hybm[ip];
8138 }
8139 }
8140
8141 /* Calculate eta levels... */
8142 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
8143 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
8144 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
8145 ERRMSG("Eta levels must be ascending!");
8146 }
8147
8148 /* Check horizontal grid spacing... */
8149 for (int ix = 2; ix < met->nx; ix++)
8150 if (fabs
8151 (fabs(met->lon[ix] - met->lon[ix - 1]) -
8152 fabs(met->lon[1] - met->lon[0])) > 0.001)
8153 ERRMSG("No regular grid spacing in longitudes!");
8154 for (int iy = 2; iy < met->ny; iy++)
8155 if (fabs
8156 (fabs(met->lat[iy] - met->lat[iy - 1]) -
8157 fabs(met->lat[1] - met->lat[0])) > 0.001) {
8158 WARN("No regular grid spacing in latitudes!");
8159 break;
8160 }
8161}
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:10918
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:9731
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:11017
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2540
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:2544
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3522
double eta[EP]
Model level eta values.
Definition: mptrac.h:3531
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3525
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3528
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 8165 of file mptrac.c.

8169 {
8170
8171 /* Set timer... */
8172 SELECT_TIMER("READ_MET_SURFACE", "INPUT");
8173 LOG(2, "Read surface data...");
8174
8175 /* Read surface pressure... */
8176 if (read_met_nc_2d
8177 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
8178 1.0f, 1)) {
8179 for (int ix = 0; ix < met->nx; ix++)
8180 for (int iy = 0; iy < met->ny; iy++)
8181 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8182 } else
8183 if (!read_met_nc_2d
8184 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
8185 0.01f, 1)) {
8186 WARN("Cannot not read surface pressure data (use lowest level)!");
8187 for (int ix = 0; ix < met->nx; ix++)
8188 for (int iy = 0; iy < met->ny; iy++)
8189 met->ps[ix][iy]
8190 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8191 }
8192
8193 /* MPTRAC meteo data... */
8194 if (ctl->met_clams == 0) {
8195
8196 /* Read geopotential height at the surface... */
8197 if (!read_met_nc_2d
8198 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8199 (float) (1. / (1000. * G0)), 1))
8200 if (!read_met_nc_2d
8201 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8202 (float) (1. / 1000.), 1))
8203 WARN("Cannot read surface geopotential height!");
8204 }
8205
8206 /* CLaMS meteo data... */
8207 else {
8208
8209 /* Read geopotential height at the surface
8210 (use lowermost level of 3-D data field)... */
8211 float *help;
8212 ALLOC(help, float,
8213 EX * EY * EP);
8214 memcpy(help, met->pl, sizeof(met->pl));
8215 if (!read_met_nc_3d
8216 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
8217 (float) (1e-3 / G0)))
8218 ERRMSG("Cannot read geopotential height!");
8219 for (int ix = 0; ix < met->nx; ix++)
8220 for (int iy = 0; iy < met->ny; iy++)
8221 met->zs[ix][iy] = met->pl[ix][iy][0];
8222 memcpy(met->pl, help, sizeof(met->pl));
8223 free(help);
8224 }
8225
8226 /* Read temperature at the surface... */
8227 if (!read_met_nc_2d
8228 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
8229 1))
8230 WARN("Cannot read surface temperature!");
8231
8232 /* Read zonal wind at the surface... */
8233 if (!read_met_nc_2d
8234 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
8235 met->us, 1.0, 1))
8236 WARN("Cannot read surface zonal wind!");
8237
8238 /* Read meridional wind at the surface... */
8239 if (!read_met_nc_2d
8240 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
8241 met->vs, 1.0, 1))
8242 WARN("Cannot read surface meridional wind!");
8243
8244 /* Read eastward turbulent surface stress... */
8245 if (!read_met_nc_2d
8246 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
8247 1.0, 1))
8248 WARN("Cannot read eastward turbulent surface stress!");
8249
8250 /* Read northward turbulent surface stress... */
8251 if (!read_met_nc_2d
8252 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
8253 1.0, 1))
8254 WARN("Cannot read nothward turbulent surface stress!");
8255
8256 /* Read surface sensible heat flux... */
8257 if (!read_met_nc_2d
8258 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
8259 1.0, 1))
8260 WARN("Cannot read surface sensible heat flux!");
8261
8262 /* Read land-sea mask... */
8263 if (!read_met_nc_2d
8264 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
8265 1.0, 1))
8266 WARN("Cannot read land-sea mask!");
8267
8268 /* Read sea surface temperature... */
8269 if (!read_met_nc_2d
8270 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
8271 1.0, 1))
8272 WARN("Cannot read sea surface temperature!");
8273
8274 /* Read PBL... */
8275 if (ctl->met_pbl == 0)
8276 if (!read_met_nc_2d
8277 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8278 0.01f, 1))
8279 WARN("Cannot read planetary boundary layer pressure!");
8280 if (ctl->met_pbl == 1)
8281 if (!read_met_nc_2d
8282 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8283 0.001f, 1))
8284 WARN("Cannot read planetary boundary layer height!");
8285
8286 /* Read CAPE... */
8287 if (ctl->met_cape == 0)
8288 if (!read_met_nc_2d
8289 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
8290 met->cape, 1.0, 1))
8291 WARN("Cannot read CAPE!");
8292
8293 /* Read CIN... */
8294 if (ctl->met_cape == 0)
8295 if (!read_met_nc_2d
8296 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
8297 1.0, 1))
8298 WARN("Cannot read convective inhibition!");
8299}
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:8500
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:8822
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 8303 of file mptrac.c.

8307 {
8308
8309 /* Set timer... */
8310 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT");
8311 LOG(2, "Read level data...");
8312
8313 /* Read temperature... */
8314 if (!read_met_nc_3d
8315 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
8316 ERRMSG("Cannot read temperature!");
8317
8318 /* Read horizontal wind and vertical velocity... */
8319 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
8320 ERRMSG("Cannot read zonal wind!");
8321 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
8322 ERRMSG("Cannot read meridional wind!");
8323 if (!read_met_nc_3d
8324 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
8325 WARN("Cannot read vertical velocity!");
8326
8327 /* Read water vapor... */
8328 if (!ctl->met_relhum) {
8329 if (!read_met_nc_3d
8330 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
8331 (float) (MA / MH2O)))
8332 WARN("Cannot read specific humidity!");
8333 } else {
8334 if (!read_met_nc_3d
8335 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
8336 WARN("Cannot read relative humidity!");
8337#pragma omp parallel for default(shared) collapse(2)
8338 for (int ix = 0; ix < met->nx; ix++)
8339 for (int iy = 0; iy < met->ny; iy++)
8340 for (int ip = 0; ip < met->np; ip++) {
8341 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
8342 met->h2o[ix][iy][ip] =
8343 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
8344 }
8345 }
8346
8347 /* Read ozone... */
8348 if (!read_met_nc_3d
8349 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
8350 (float) (MA / MO3)))
8351 WARN("Cannot read ozone data!");
8352
8353 /* Read cloud data... */
8354 if (!read_met_nc_3d
8355 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
8356 WARN("Cannot read cloud liquid water content!");
8357 if (!read_met_nc_3d
8358 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
8359 WARN("Cannot read cloud rain water content!");
8360 if (!read_met_nc_3d
8361 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
8362 WARN("Cannot read cloud ice water content!");
8363 if (!read_met_nc_3d
8364 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
8365 WARN("Cannot read cloud snow water content!");
8366 if (!read_met_nc_3d
8367 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
8368 WARN("Cannot read cloud cover!");
8369
8370 /* Read zeta and zeta_dot... */
8371 if (ctl->advect_vert_coord == 1) {
8372 if (!read_met_nc_3d
8373 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
8374 WARN("Cannot read ZETA!");
8375 if (!read_met_nc_3d
8376 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
8377 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
8378 WARN("Cannot read ZETA_DOT!");
8379 }
8380
8381 /* Read eta and eta_dot... */
8382 else if (ctl->advect_vert_coord == 3) {
8383#pragma omp parallel for default(shared)
8384 for (int ix = 0; ix < met->nx; ix++)
8385 for (int iy = 0; iy < met->ny; iy++)
8386 for (int ip = 0; ip < met->np; ip++)
8387 met->zetal[ix][iy][ip] =
8388 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
8389 if (!read_met_nc_3d
8390 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
8391 1.0))
8392 WARN("Cannot read eta vertical velocity!");
8393 }
8394
8395 /* Store velocities on model levels... */
8396 if (ctl->met_vert_coord != 0) {
8397#pragma omp parallel for default(shared)
8398 for (int ix = 0; ix < met->nx; ix++)
8399 for (int iy = 0; iy < met->ny; iy++)
8400 for (int ip = 0; ip < met->np; ip++) {
8401 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
8402 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
8403 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
8404 }
8405
8406 /* Save number of model levels... */
8407 met->npl = met->np;
8408 }
8409
8410 /* Get pressure on model levels... */
8411 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
8412
8413 /* Read 3-D pressure field... */
8414 if (ctl->met_vert_coord == 1) {
8415 if (!read_met_nc_3d
8416 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
8417 0.01f))
8418 if (!read_met_nc_3d
8419 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
8420 ERRMSG("Cannot read pressure on model levels!");
8421 }
8422
8423 /* Use a and b coefficients for full levels (at layer midpoints)... */
8424 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
8425
8426 /* Check number of levels... */
8427 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
8428 ERRMSG("Mismatch in number of model levels!");
8429
8430 /* Calculate pressure... */
8431 for (int ix = 0; ix < met->nx; ix++)
8432 for (int iy = 0; iy < met->ny; iy++)
8433 for (int ip = 0; ip < met->np; ip++)
8434 met->pl[ix][iy][ip] =
8435 (float) (met->hyam[ip] / 100. +
8436 met->hybm[ip] * met->ps[ix][iy]);
8437 }
8438
8439 /* Use a and b coefficients for half levels (at layer interfaces)... */
8440 else if (ctl->met_vert_coord == 4) {
8441
8442 /* Check number of levels... */
8443 if (met->np + 1 != ctl->met_nlev)
8444 ERRMSG("Mismatch in number of model levels!");
8445
8446 /* Calculate pressure... */
8447#pragma omp parallel for default(shared) collapse(2)
8448 for (int ix = 0; ix < met->nx; ix++)
8449 for (int iy = 0; iy < met->ny; iy++)
8450 for (int ip = 0; ip < met->np; ip++) {
8451 const double p0 =
8452 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
8453 const double p1 =
8454 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
8455 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
8456 }
8457 }
8458
8459 /* Check ordering of pressure levels... */
8460 for (int ix = 0; ix < met->nx; ix++)
8461 for (int iy = 0; iy < met->ny; iy++)
8462 for (int ip = 1; ip < met->np; ip++)
8463 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
8464 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
8465 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
8466 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
8467 ERRMSG("Pressure profiles are not monotonic!");
8468 }
8469
8470 /* Interpolate from model levels to pressure levels... */
8471 if (ctl->met_np > 0) {
8472
8473 /* Interpolate variables... */
8474 read_met_ml2pl(ctl, met, met->t, "T");
8475 read_met_ml2pl(ctl, met, met->u, "U");
8476 read_met_ml2pl(ctl, met, met->v, "V");
8477 read_met_ml2pl(ctl, met, met->w, "W");
8478 read_met_ml2pl(ctl, met, met->h2o, "H2O");
8479 read_met_ml2pl(ctl, met, met->o3, "O3");
8480 read_met_ml2pl(ctl, met, met->lwc, "LWC");
8481 read_met_ml2pl(ctl, met, met->rwc, "RWC");
8482 read_met_ml2pl(ctl, met, met->iwc, "IWC");
8483 read_met_ml2pl(ctl, met, met->swc, "SWC");
8484 read_met_ml2pl(ctl, met, met->cc, "CC");
8485
8486 /* Set new pressure levels... */
8487 met->np = ctl->met_np;
8488 for (int ip = 0; ip < met->np; ip++)
8489 met->p[ip] = ctl->met_p[ip];
8490 }
8491
8492 /* Check ordering of pressure levels... */
8493 for (int ip = 1; ip < met->np; ip++)
8494 if (met->p[ip - 1] < met->p[ip])
8495 ERRMSG("Pressure levels must be descending!");
8496}
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:9564
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:291
#define MO3
Molar mass of ozone [g/mol].
Definition: mptrac.h:296
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 8500 of file mptrac.c.

8513 {
8514
8515 char varsel[LEN];
8516
8517 float offset, scalfac;
8518
8519 int varid;
8520
8521 /* Check if variable exists... */
8522 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8523 sprintf(varsel, "%s", varname);
8524 else if (varname2 != NULL
8525 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8526 sprintf(varsel, "%s", varname2);
8527 else if (varname3 != NULL
8528 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8529 sprintf(varsel, "%s", varname3);
8530 else if (varname4 != NULL
8531 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8532 sprintf(varsel, "%s", varname4);
8533 else if (varname5 != NULL
8534 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
8535 sprintf(varsel, "%s", varname5);
8536 else if (varname6 != NULL
8537 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
8538 sprintf(varsel, "%s", varname6);
8539 else
8540 return 0;
8541
8542 /* Read packed data... */
8543 if (ctl->met_nc_scale && !ctl->dd
8544 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8545 && nc_get_att_float(ncid, varid, "scale_factor",
8546 &scalfac) == NC_NOERR) {
8547
8548 /* Allocate... */
8549 short *help;
8550 ALLOC(help, short,
8551 EX * EY * EP);
8552
8553 /* Read fill value and missing value... */
8554 short fillval, missval;
8555 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8556 fillval = 0;
8557 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
8558 missval = 0;
8559
8560 /* Write info... */
8561 LOG(2, "Read 2-D variable: %s"
8562 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
8563 varsel, fillval, missval, scalfac, offset);
8564
8565 /* Read data... */
8566 NC(nc_get_var_short(ncid, varid, help));
8567
8568 /* Check meteo data layout... */
8569 if (ctl->met_convention != 0)
8570 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
8571
8572 /* Copy and check data... */
8573 omp_set_dynamic(1);
8574#pragma omp parallel for default(shared)
8575 for (int ix = 0; ix < met->nx; ix++)
8576 for (int iy = 0; iy < met->ny; iy++) {
8577 if (init)
8578 dest[ix][iy] = 0;
8579 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
8580 if ((fillval == 0 || aux != fillval)
8581 && (missval == 0 || aux != missval)
8582 && fabsf(aux * scalfac + offset) < 1e14f)
8583 dest[ix][iy] += scl * (aux * scalfac + offset);
8584 else
8585 dest[ix][iy] = NAN;
8586 }
8587 omp_set_dynamic(0);
8588
8589 /* Free... */
8590 free(help);
8591 }
8592
8593 /* Unpacked data... */
8594 else if (!ctl->dd) {
8595
8596 /* Allocate... */
8597 float *help;
8598 ALLOC(help, float,
8599 EX * EY);
8600
8601 /* Read fill value and missing value... */
8602 float fillval, missval;
8603 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8604 fillval = 0;
8605 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8606 missval = 0;
8607
8608 /* Write info... */
8609 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8610 varsel, fillval, missval);
8611
8612 /* Read data... */
8613 NC(nc_get_var_float(ncid, varid, help));
8614
8615 /* Check meteo data layout... */
8616 if (ctl->met_convention == 0) {
8617
8618 /* Copy and check data (ordering: lat, lon)... */
8619 omp_set_dynamic(1);
8620#pragma omp parallel for default(shared)
8621 for (int ix = 0; ix < met->nx; ix++)
8622 for (int iy = 0; iy < met->ny; iy++) {
8623 if (init)
8624 dest[ix][iy] = 0;
8625 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
8626 if ((fillval == 0 || aux != fillval)
8627 && (missval == 0 || aux != missval)
8628 && fabsf(aux) < 1e14f)
8629 dest[ix][iy] += scl * aux;
8630 else
8631 dest[ix][iy] = NAN;
8632 }
8633 omp_set_dynamic(0);
8634
8635 } else {
8636
8637 /* Copy and check data (ordering: lon, lat)... */
8638 omp_set_dynamic(1);
8639#pragma omp parallel for default(shared)
8640 for (int iy = 0; iy < met->ny; iy++)
8641 for (int ix = 0; ix < met->nx; ix++) {
8642 if (init)
8643 dest[ix][iy] = 0;
8644 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
8645 if ((fillval == 0 || aux != fillval)
8646 && (missval == 0 || aux != missval)
8647 && fabsf(aux) < 1e14f)
8648 dest[ix][iy] += scl * aux;
8649 else
8650 dest[ix][iy] = NAN;
8651 }
8652 omp_set_dynamic(0);
8653 }
8654
8655 /* Free... */
8656 free(help);
8657 }
8658
8659 /* Domain decomposed data... */
8660 else {
8661
8662 /* Read fill value and missing value... */
8663 float fillval, missval;
8664 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8665 fillval = 0;
8666 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8667 missval = 0;
8668
8669 /* Write info... */
8670 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8671 varsel, fillval, missval);
8672
8673 /* Define hyperslab... */
8674 float *help;
8675 size_t help_subdomain_start[3];
8676 size_t help_subdomain_count[3];
8677
8678 help_subdomain_start[0] = 0;
8679 if (ctl->met_convention == 0) {
8680 help_subdomain_start[1] = dd->subdomain_start[2];
8681 help_subdomain_start[2] = dd->subdomain_start[3];
8682 } else {
8683 help_subdomain_start[1] = dd->subdomain_start[3];
8684 help_subdomain_start[2] = dd->subdomain_start[2];
8685 }
8686
8687 help_subdomain_count[0] = 1;
8688 if (ctl->met_convention == 0) {
8689 help_subdomain_count[1] = dd->subdomain_count[2]; //y
8690 help_subdomain_count[2] = dd->subdomain_count[3]; //x
8691 } else {
8692 help_subdomain_count[1] = dd->subdomain_count[3]; //x
8693 help_subdomain_count[2] = dd->subdomain_count[2]; //y
8694 }
8695
8696 ALLOC(help, float,
8697 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
8698
8699 /* Read data... */
8700#ifdef DD
8701 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
8702#endif
8703 NC(nc_get_vara_float
8704 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
8705
8706 /* Read halos at boundaries... */
8707 size_t help_halo_bnd_start[3];
8708 size_t help_halo_bnd_count[3];
8709
8710 help_halo_bnd_start[0] = 0;
8711 if (ctl->met_convention == 0) {
8712 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
8713 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
8714 } else {
8715 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
8716 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
8717 }
8718
8719 help_halo_bnd_count[0] = 1;
8720 if (ctl->met_convention == 0) {
8721 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
8722 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
8723 } else {
8724 help_halo_bnd_count[1] = dd->halo_bnd_count[3]; //x
8725 help_halo_bnd_count[2] = dd->halo_bnd_count[2]; //y
8726 }
8727
8728 float *help_halo;
8729 ALLOC(help_halo, float,
8730 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
8731
8732#ifdef DD
8733 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
8734#endif
8735 NC(nc_get_vara_float
8736 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
8737
8738 /* Check meteo data layout... */
8739 if (ctl->met_convention == 0) {
8740
8741 /* Copy and check data (ordering: lat, lon)... */
8742 omp_set_dynamic(1);
8743#pragma omp parallel for default(shared)
8744 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
8745 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
8746 if (init == 1)
8747 dest[ix + dd->halo_offset_start][iy] = 0;
8748 const float aux =
8749 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
8750 if ((fillval == 0 || aux != fillval)
8751 && (missval == 0 || aux != missval)
8752 && fabsf(aux) < 1e14f) {
8753 dest[ix + dd->halo_offset_start][iy] += scl * aux;
8754 } else
8755 dest[ix + dd->halo_offset_start][iy] = NAN;
8756 }
8757
8758#pragma omp parallel for default(shared)
8759 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
8760 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
8761 if (init == 1)
8762 dest[ix + dd->halo_offset_end][iy] = 0;
8763 const float aux =
8764 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
8765 if ((fillval == 0 || aux != fillval)
8766 && (missval == 0 || aux != missval)
8767 && fabsf(aux) < 1e14f)
8768 dest[ix + dd->halo_offset_end][iy] += scl * aux;
8769 else {
8770 dest[ix + dd->halo_offset_end][iy] = NAN;
8771 }
8772 }
8773 omp_set_dynamic(0);
8774
8775 } else {
8776
8777 /* Copy and check data (ordering: lon, lat)... */
8778 omp_set_dynamic(1);
8779#pragma omp parallel for default(shared)
8780 for (int ix = 0; ix < (int) help_subdomain_count[1]; ix++)
8781 for (int iy = 0; iy < (int) help_subdomain_count[2]; iy++) {
8782 if (init == 1)
8783 dest[ix + dd->halo_offset_start][iy] = 0;
8784 const float aux =
8785 help[ARRAY_2D(ix, iy, (int) help_subdomain_count[1])];
8786 if ((fillval == 0 || aux != fillval)
8787 && (missval == 0 || aux != missval)
8788 && fabsf(aux) < 1e14f)
8789 dest[ix + dd->halo_offset_start][iy] += scl * aux;
8790 else
8791 dest[ix + dd->halo_offset_start][iy] = NAN;
8792 }
8793
8794#pragma omp parallel for default(shared)
8795 for (int ix = 0; ix < (int) help_halo_bnd_count[1]; ix++)
8796 for (int iy = 0; iy < (int) help_halo_bnd_count[2]; iy++) {
8797 if (init == 1)
8798 dest[ix + dd->halo_offset_end][iy] = 0;
8799 const float aux =
8800 help_halo[ARRAY_2D(ix, iy, (int) help_halo_bnd_count[1])];
8801 if ((fillval == 0 || aux != fillval)
8802 && (missval == 0 || aux != missval)
8803 && fabsf(aux) < 1e14f)
8804 dest[ix + dd->halo_offset_end][iy] += scl * aux;
8805 else
8806 dest[ix + dd->halo_offset_end][iy] = NAN;
8807 }
8808 omp_set_dynamic(0);
8809 }
8810
8811 /* Free... */
8812 free(help);
8813 free(help_halo);
8814 }
8815
8816 /* Return... */
8817 return 1;
8818}
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2554
size_t halo_bnd_count[4]
Extent of the periodic boundary halo hyperslab.
Definition: mptrac.h:3701
int halo_offset_end
Offset of the periodic halo block at the end of the local x-array.
Definition: mptrac.h:3707
size_t halo_bnd_start[4]
Start indices of the periodic boundary halo hyperslab.
Definition: mptrac.h:3698
int halo_offset_start
Offset of the periodic halo block at the beginning of the local x-array.
Definition: mptrac.h:3704
size_t subdomain_count[4]
Extent of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:3695
size_t subdomain_start[4]
Start indices of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:3692

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

8832 {
8833
8834 SELECT_TIMER("read_met_nc_3d", "INPUT");
8835
8836 char varsel[LEN];
8837
8838 float offset, scalfac;
8839
8840 int varid;
8841
8842 /* Check if variable exists... */
8843 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8844 sprintf(varsel, "%s", varname);
8845 else if (varname2 != NULL
8846 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8847 sprintf(varsel, "%s", varname2);
8848 else if (varname3 != NULL
8849 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8850 sprintf(varsel, "%s", varname3);
8851 else if (varname4 != NULL
8852 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8853 sprintf(varsel, "%s", varname4);
8854 else
8855 return 0;
8856
8857 /* Read packed data... */
8858 if (ctl->met_nc_scale && !ctl->dd
8859 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8860 && nc_get_att_float(ncid, varid, "scale_factor",
8861 &scalfac) == NC_NOERR) {
8862
8863 /* Allocate... */
8864 short *help;
8865 ALLOC(help, short,
8866 EX * EY * EP);
8867
8868 /* Read fill value and missing value... */
8869 short fillval, missval;
8870 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8871 fillval = 0;
8872 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
8873 missval = 0;
8874
8875 /* Write info... */
8876 LOG(2, "Read 3-D variable: %s "
8877 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
8878 varsel, fillval, missval, scalfac, offset);
8879
8880 /* Read data... */
8881 NC(nc_get_var_short(ncid, varid, help));
8882
8883 /* Check meteo data layout... */
8884 if (ctl->met_convention != 0)
8885 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
8886
8887 /* Copy and check data... */
8888 omp_set_dynamic(1);
8889#pragma omp parallel for default(shared)
8890 for (int ix = 0; ix < met->nx; ix++)
8891 for (int iy = 0; iy < met->ny; iy++)
8892 for (int ip = 0; ip < met->np; ip++) {
8893 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
8894 if ((fillval == 0 || aux != fillval)
8895 && (missval == 0 || aux != missval)
8896 && fabsf(aux * scalfac + offset) < 1e14f)
8897 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
8898 else
8899 dest[ix][iy][ip] = NAN;
8900 }
8901 omp_set_dynamic(0);
8902
8903 /* Free... */
8904 free(help);
8905 }
8906
8907 /* Unpacked data... */
8908 else if (!ctl->dd) {
8909
8910 /* Allocate... */
8911 float *help;
8912 ALLOC(help, float,
8913 EX * EY * EP);
8914
8915 /* Read fill value and missing value... */
8916 float fillval, missval;
8917 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8918 fillval = 0;
8919 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8920 missval = 0;
8921
8922 /* Write info... */
8923 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
8924 varsel, fillval, missval);
8925
8926 /* Read data... */
8927 NC(nc_get_var_float(ncid, varid, help));
8928
8929 /* Check meteo data layout... */
8930 if (ctl->met_convention == 0) {
8931
8932 /* Copy and check data (ordering: lev, lat, lon)... */
8933 omp_set_dynamic(1);
8934#pragma omp parallel for default(shared)
8935 for (int ix = 0; ix < met->nx; ix++)
8936 for (int iy = 0; iy < met->ny; iy++)
8937 for (int ip = 0; ip < met->np; ip++) {
8938 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
8939 if ((fillval == 0 || aux != fillval)
8940 && (missval == 0 || aux != missval)
8941 && fabsf(aux) < 1e14f)
8942 dest[ix][iy][ip] = scl * aux;
8943 else
8944 dest[ix][iy][ip] = NAN;
8945 }
8946 omp_set_dynamic(0);
8947
8948 } else {
8949
8950 /* Copy and check data (ordering: lon, lat, lev)... */
8951 omp_set_dynamic(1);
8952#pragma omp parallel for default(shared)
8953 for (int ip = 0; ip < met->np; ip++)
8954 for (int iy = 0; iy < met->ny; iy++)
8955 for (int ix = 0; ix < met->nx; ix++) {
8956 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
8957 if ((fillval == 0 || aux != fillval)
8958 && (missval == 0 || aux != missval)
8959 && fabsf(aux) < 1e14f)
8960 dest[ix][iy][ip] = scl * aux;
8961 else
8962 dest[ix][iy][ip] = NAN;
8963 }
8964 omp_set_dynamic(0);
8965 }
8966
8967 /* Free... */
8968 free(help);
8969 }
8970
8971 /* Domain decomposed data... */
8972 else {
8973
8974 /* Read fill value and missing value... */
8975 float fillval, missval;
8976 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8977 fillval = 0;
8978 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8979 missval = 0;
8980
8981 /* Write info... */
8982 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
8983 varsel, fillval, missval);
8984
8985 SELECT_TIMER("read_met_nc_3d_CP1", "INPUT");
8986
8987 /* Define hyperslab... */
8988 size_t help_subdomain_start[4];
8989 size_t help_subdomain_count[4];
8990 size_t help_halo_bnd_start[4];
8991 size_t help_halo_bnd_count[4];
8992
8993 if (ctl->met_convention == 0) {
8994 for (int i = 0; i < 4; i++) {
8995 help_subdomain_start[i] = dd->subdomain_start[i];
8996 help_subdomain_count[i] = dd->subdomain_count[i];
8997 help_halo_bnd_start[i] = dd->halo_bnd_start[i];
8998 help_halo_bnd_count[i] = dd->halo_bnd_count[i];
8999 }
9000 } else {
9001 help_subdomain_start[0] = dd->subdomain_start[0];
9002 help_subdomain_start[1] = dd->subdomain_start[3];
9003 help_subdomain_start[2] = dd->subdomain_start[2];
9004 help_subdomain_start[3] = dd->subdomain_start[1];
9005
9006 help_subdomain_count[0] = dd->subdomain_count[0];
9007 help_subdomain_count[1] = dd->subdomain_count[3];
9008 help_subdomain_count[2] = dd->subdomain_count[2];
9009 help_subdomain_count[3] = dd->subdomain_count[1];
9010
9011 help_halo_bnd_start[0] = dd->halo_bnd_start[0];
9012 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
9013 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
9014 help_halo_bnd_start[3] = dd->halo_bnd_start[1];
9015
9016 help_halo_bnd_count[0] = dd->halo_bnd_count[0];
9017 help_halo_bnd_count[1] = dd->halo_bnd_count[3];
9018 help_halo_bnd_count[2] = dd->halo_bnd_count[2];
9019 help_halo_bnd_count[3] = dd->halo_bnd_count[1];
9020 }
9021
9022 /* Allocate... */
9023 float *help;
9024 ALLOC(help, float,
9025 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
9026 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
9027
9028 SELECT_TIMER("read_met_nc_3d_CP2", "INPUT");
9029
9030 /* Use default NetCDF parallel I/O behavior */
9031#ifdef DD
9032 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
9033#endif
9034 NC(nc_get_vara_float
9035 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
9036
9037 /* Read halos separately at boundaries... */
9038 float *help_halo;
9039 ALLOC(help_halo, float,
9040 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
9041 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
9042
9043 SELECT_TIMER("read_met_nc_3d_CP3", "INPUT");
9044
9045 /* Halo read also uses independent access */
9046#ifdef DD
9047 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
9048#endif
9049 NC(nc_get_vara_float(ncid,
9050 varid,
9051 help_halo_bnd_start, help_halo_bnd_count,
9052 help_halo));
9053
9054 SELECT_TIMER("read_met_nc_3d_CP4", "INPUT");
9055
9056 /* Check meteo data layout... */
9057 if (ctl->met_convention == 0) {
9058
9059 /* Copy and check data (ordering: lev, lat, lon)... */
9060 omp_set_dynamic(1);
9061#pragma omp parallel for default(shared)
9062 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9063 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9064 for (int ip = 0; ip < met->np; ip++) {
9065 const float aux =
9066 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
9067 (int) dd->subdomain_count[3])];
9068 if ((fillval == 0 || aux != fillval)
9069 && (missval == 0 || aux != missval)
9070 && fabsf(aux) < 1e14f)
9071 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9072 else
9073 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9074 }
9075
9076#pragma omp parallel for default(shared)
9077 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9078 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9079 for (int ip = 0; ip < met->np; ip++) {
9080 const float aux =
9081 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
9082 (int) dd->halo_bnd_count[3])];
9083 if ((fillval == 0 || aux != fillval)
9084 && (missval == 0 || aux != missval)
9085 && fabsf(aux) < 1e14f)
9086 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9087 else
9088 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9089 }
9090 omp_set_dynamic(0);
9091
9092 } else {
9093
9094 /* Copy and check data (ordering: lon, lat, lev)... */
9095 omp_set_dynamic(1);
9096#pragma omp parallel for default(shared)
9097 for (int ip = 0; ip < met->np; ip++)
9098 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9099 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
9100 const float aux =
9101 help[ARRAY_3D
9102 (ix, iy, (int) dd->subdomain_count[2], ip, met->np)];
9103 if ((fillval == 0 || aux != fillval)
9104 && (missval == 0 || aux != missval)
9105 && fabsf(aux) < 1e14f)
9106 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9107 else
9108 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9109 }
9110
9111#pragma omp parallel for default(shared)
9112 for (int ip = 0; ip < met->np; ip++)
9113 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9114 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
9115 const float aux =
9116 help_halo[ARRAY_3D(ix, iy, (int) dd->halo_bnd_count[2], ip,
9117 met->np)];
9118 if ((fillval == 0 || aux != fillval)
9119 && (missval == 0 || aux != missval)
9120 && fabsf(aux) < 1e14f)
9121 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9122 else
9123 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9124 }
9125 omp_set_dynamic(0);
9126 }
9127
9128 /* Free... */
9129 free(help);
9130 free(help_halo);
9131 }
9132
9133 /* Return... */
9134 return 1;
9135}

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

9568 {
9569
9570 double aux[EP], p[EP];
9571
9572 /* Set timer... */
9573 SELECT_TIMER("READ_MET_ML2PL", "METPROC");
9574 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
9575
9576 /* Loop over columns... */
9577#pragma omp parallel for default(shared) private(aux,p) collapse(2)
9578 for (int ix = 0; ix < met->nx; ix++)
9579 for (int iy = 0; iy < met->ny; iy++) {
9580
9581 /* Copy pressure profile... */
9582 for (int ip = 0; ip < met->np; ip++)
9583 p[ip] = met->pl[ix][iy][ip];
9584
9585 /* Interpolate... */
9586 for (int ip = 0; ip < ctl->met_np; ip++) {
9587 double pt = ctl->met_p[ip];
9588 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
9589 pt = p[0];
9590 else if ((pt > p[met->np - 1] && p[1] > p[0])
9591 || (pt < p[met->np - 1] && p[1] < p[0]))
9592 pt = p[met->np - 1];
9593 const int ip2 = locate_irr(p, met->np, pt);
9594 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
9595 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
9596 }
9597
9598 /* Copy data... */
9599 for (int ip = 0; ip < ctl->met_np; ip++)
9600 var[ix][iy][ip] = (float) aux[ip];
9601 }
9602}
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 9606 of file mptrac.c.

9608 {
9609
9610 /* Check parameters... */
9611 if (ctl->advect_vert_coord != 1)
9612 return;
9613
9614 /* Set timer... */
9615 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC");
9616 LOG(2, "Make zeta profiles monotone...");
9617
9618 /* Create monotone zeta profiles... */
9619#pragma omp parallel for default(shared) collapse(2)
9620 for (int i = 0; i < met->nx; i++)
9621 for (int j = 0; j < met->ny; j++) {
9622 int k = 1;
9623
9624 while (k < met->npl) { /* Check if there is an inversion at level k... */
9625 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
9626 /* Find the upper level k+l over the inversion... */
9627 int l = 0;
9628 do {
9629 l++;
9630 }
9631 while ((met->zetal[i][j][k - 1] >=
9632 met->zetal[i][j][k + l]) & (k + l < met->npl));
9633
9634 /* Interpolate linear between the top and bottom
9635 of the inversion... */
9636 float s =
9637 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
9638 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9639
9640 for (int m = k; m < k + l; m++) {
9641 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9642 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
9643 }
9644
9645 /* Search for more inversions above the last inversion ... */
9646 k = k + l;
9647 } else {
9648 k++;
9649 }
9650 }
9651 }
9652
9653 /* Create monotone pressure profiles... */
9654#pragma omp parallel for default(shared) collapse(2)
9655 for (int i = 0; i < met->nx; i++)
9656 for (int j = 0; j < met->ny; j++) {
9657 int k = 1;
9658
9659 while (k < met->npl) { /* Check if there is an inversion at level k... */
9660 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
9661
9662 /* Find the upper level k+l over the inversion... */
9663 int l = 0;
9664 do {
9665 l++;
9666 }
9667 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
9668 met->npl));
9669
9670 /* Interpolate linear between the top and bottom
9671 of the inversion... */
9672 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
9673 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9674
9675 for (int m = k; m < k + l; m++) {
9676 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9677 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
9678 }
9679
9680 /* Search for more inversions above the last inversion ... */
9681 k += l;
9682 } else {
9683 k++;
9684 }
9685 }
9686 }
9687}

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

9695 {
9696
9697 int ncid;
9698
9699 /* Open file... */
9700#ifdef DD
9701 if (ctl->dd) {
9702 NC(nc_open_par
9703 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
9704 &ncid))
9705 }
9706#else
9707 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
9708 WARN("Cannot open file!");
9709 return 0;
9710 }
9711#endif
9712
9713 /* Read coordinates of meteo data... */
9714 read_met_nc_grid(filename, ncid, ctl, met, dd);
9715
9716 /* Read surface data... */
9717 read_met_nc_surface(ncid, ctl, met, dd);
9718
9719 /* Read meteo data on vertical levels... */
9720 read_met_nc_levels(ncid, ctl, met, dd);
9721
9722 /* Close file... */
9723 NC(nc_close(ncid));
9724
9725 /* Return success... */
9726 return 1;
9727}
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:8303
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:8165
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:7998
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 9731 of file mptrac.c.

9735 {
9736
9737 int varid;
9738
9739 /* Get the MPI information... */
9740 int rank = 0, size = 1;
9741#ifdef MPI
9742 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
9743 MPI_Comm_size(MPI_COMM_WORLD, &size);
9744#endif
9745
9746 /* Get grid dimensions... */
9747 NC_INQ_DIM("lon", &dd->nx_glob, 0, 0, 0);
9748 NC_INQ_DIM("lat", &dd->ny_glob, 0, 0, 0);
9749
9750 LOG(2, "Number of longitudes: %d", dd->nx_glob);
9751 LOG(2, "Number of latitudes: %d", dd->ny_glob);
9752
9753 /* Check grid... */
9754 if (dd->nx_glob > DD_EX_GLOB || dd->ny_glob > DD_EY_GLOB)
9755 ERRMSG("Global grid is too large!");
9756
9757 if (ctl->dd_subdomains_zonal > dd->nx_glob)
9758 ERRMSG("Too many zonal subdomains for global x grid!");
9759
9760 if (ctl->dd_subdomains_meridional > dd->ny_glob)
9761 ERRMSG("Too many meridional subdomains for global y grid!");
9762
9763 /* Read global longitudes and latitudes... */
9764 NC_GET_DOUBLE("lon", dd->lon_glob, 1);
9765 NC_GET_DOUBLE("lat", dd->lat_glob, 1);
9766
9767 LOG(2, "Longitudes: %g, %g ... %g deg",
9768 dd->lon_glob[0], dd->lon_glob[1], dd->lon_glob[dd->nx_glob - 1]);
9769 LOG(2, "Latitudes: %g, %g ... %g deg",
9770 dd->lat_glob[0], dd->lat_glob[1], dd->lat_glob[dd->ny_glob - 1]);
9771
9772 /* Rank coordinates in DD layout... */
9773 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
9774 const int merid_rank = rank % ctl->dd_subdomains_meridional;
9775
9776 /* Check for edge cases... */
9777 const int left = (zonal_rank == 0);
9778 const int right = (zonal_rank == ctl->dd_subdomains_zonal - 1);
9779 const int top = (merid_rank == 0);
9780 const int bottom = (merid_rank == ctl->dd_subdomains_meridional - 1);
9781
9782 /* Core owned block (without halos)... */
9783 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
9784 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
9785
9786 const int ix0 = zonal_rank * nx_block;
9787 const int iy0 = merid_rank * ny_block;
9788
9789 int nx_core = nx_block;
9790 int ny_core = ny_block;
9791
9792 if (right)
9793 nx_core += dd->nx_glob - ctl->dd_subdomains_zonal * nx_block;
9794 if (bottom)
9795 ny_core += dd->ny_glob - ctl->dd_subdomains_meridional * ny_block;
9796
9797 /* Store core met size first... */
9798 met->nx = nx_core;
9799 met->ny = ny_core;
9800
9801 /* Set hyperslab for core subdomain... */
9802 dd->subdomain_start[0] = 0;
9803 dd->subdomain_start[1] = 0;
9804 dd->subdomain_start[2] = (size_t) iy0;
9805 dd->subdomain_start[3] = (size_t) ix0;
9806
9807 dd->subdomain_count[0] = 1;
9808 dd->subdomain_count[1] = (size_t) met->np;
9809 dd->subdomain_count[2] = (size_t) ny_core;
9810 dd->subdomain_count[3] = (size_t) nx_core;
9811
9812 /* Add inner halos to read window... */
9813 if (!left && !right) {
9814 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
9815 dd->subdomain_count[3] += (size_t) (2 * ctl->dd_halos_size);
9816 } else if (left ^ right) {
9817 dd->subdomain_count[3] += (size_t) ctl->dd_halos_size;
9818 if (!left)
9819 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
9820 }
9821
9822 if (!top && !bottom) {
9823 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
9824 dd->subdomain_count[2] += (size_t) (2 * ctl->dd_halos_size);
9825 } else if (top ^ bottom) {
9826 dd->subdomain_count[2] += (size_t) ctl->dd_halos_size;
9827 if (!top)
9828 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
9829 }
9830
9831 /* Set boundary halo hyperslabs... */
9832 double lon_shift = 0.0;
9833
9834 if (left ^ right) {
9835 dd->halo_bnd_start[0] = 0;
9836 dd->halo_bnd_start[1] = 0;
9837 dd->halo_bnd_start[2] = dd->subdomain_start[2];
9838 dd->halo_bnd_start[3] =
9839 (size_t) (left ? (dd->nx_glob - ctl->dd_halos_size) : 0);
9840
9841 dd->halo_bnd_count[0] = 1;
9842 dd->halo_bnd_count[1] = (size_t) met->np;
9843 dd->halo_bnd_count[2] =
9844 (size_t) met->ny +
9845 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
9846 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
9847
9848 dd->halo_offset_start = left ? (int) dd->halo_bnd_count[3] : 0;
9849 dd->halo_offset_end = left ? 0 : (int) dd->subdomain_count[3];
9850 lon_shift = left ? -360.0 : 360.0;
9851 } else {
9852 dd->halo_bnd_start[0] = 0;
9853 dd->halo_bnd_start[1] = 0;
9854 dd->halo_bnd_start[2] = 0;
9855 dd->halo_bnd_start[3] = 0;
9856
9857 dd->halo_bnd_count[0] = 0;
9858 dd->halo_bnd_count[1] = 0;
9859 dd->halo_bnd_count[2] = 0;
9860 dd->halo_bnd_count[3] = 0;
9861
9862 dd->halo_offset_start = 0;
9863 dd->halo_offset_end = 0;
9864 }
9865
9866 /* Focus on subdomain latitudes... */
9867 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9868 met->lat[iy] = dd->lat_glob[(int) dd->subdomain_start[2] + iy];
9869
9870 /* Focus on subdomain longitudes... */
9871 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9872 met->lon[ix + dd->halo_offset_start] =
9873 dd->lon_glob[(int) dd->subdomain_start[3] + ix];
9874
9875 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9876 met->lon[ix + dd->halo_offset_end] =
9877 dd->lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
9878
9879 /* Reset halo-extended grid dimensions... */
9880 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
9881 met->ny = (int) dd->subdomain_count[2];
9882
9883 LOG(2, "Define subdomain properties.");
9884 LOG(2, "MPI information: Rank %d, Size %d", rank, size);
9885 LOG(2, "Edge position: l=%d,r=%d,t=%d,b=%d", left, right, top, bottom);
9886 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d",
9887 met->nx, met->ny, met->np);
9888 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
9889 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
9890 (int) dd->halo_bnd_count[1]);
9891 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
9892 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
9893 (int) dd->subdomain_count[1]);
9894 LOG(2, "Subdomain start: nx %ld ny %ld np %ld",
9895 dd->subdomain_start[3], dd->subdomain_start[2], dd->subdomain_start[1]);
9896 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld",
9897 dd->halo_bnd_start[3], dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
9898 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
9899 LOG(2, "%d Subdomain longitudes: %g, %g ... %g deg",
9900 rank, met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9901 LOG(2, "%d Subdomain latitudes: %g, %g ... %g deg",
9902 rank, met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9903}
#define DD_EY_GLOB
Maximum number of latitudes of global meteo data.
Definition: mptrac.h:420
#define DD_EX_GLOB
Maximum number of longitudes of global meteo data.
Definition: mptrac.h:415
double lon_glob[DD_EX_GLOB]
Longitudes of the global grid [deg].
Definition: mptrac.h:3682
double lat_glob[DD_EY_GLOB]
Latitudes of the global grid [deg].
Definition: mptrac.h:3685
int ny_glob
Number of global latitudes.
Definition: mptrac.h:3679

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

9909 {
9910
9911 /* Set timer... */
9912 SELECT_TIMER("READ_MET_PBL", "METPROC");
9913 LOG(2, "Calculate planetary boundary layer...");
9914
9915 /* Convert PBL height from meteo file to pressure... */
9916 if (ctl->met_pbl == 1) {
9917
9918 /* Loop over grid points... */
9919#pragma omp parallel for default(shared) collapse(2)
9920 for (int ix = 0; ix < met->nx; ix++)
9921 for (int iy = 0; iy < met->ny; iy++) {
9922
9923 /* Get pressure at top of PBL... */
9924 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
9925 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
9926 met->pbl[ix][iy] =
9927 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
9928 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
9929 }
9930 }
9931
9932 /* Determine PBL based on Richardson number... */
9933 else if (ctl->met_pbl == 2) {
9934
9935 /* Parameters used to estimate the height of the PBL
9936 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
9937 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
9938
9939 /* Loop over grid points... */
9940#pragma omp parallel for default(shared) collapse(2)
9941 for (int ix = 0; ix < met->nx; ix++)
9942 for (int iy = 0; iy < met->ny; iy++) {
9943
9944 /* Set bottom level of PBL... */
9945 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
9946
9947 /* Find lowest level near the bottom... */
9948 int ip;
9949 for (ip = 1; ip < met->np; ip++)
9950 if (met->p[ip] < pbl_bot)
9951 break;
9952
9953 /* Get near surface data... */
9954 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
9955 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
9956 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
9957
9958 /* Init... */
9959 double rib_old = 0;
9960
9961 /* Loop over levels... */
9962 for (; ip < met->np; ip++) {
9963
9964 /* Get squared horizontal wind speed... */
9965 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
9966 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
9967 vh2 = MAX(vh2, SQR(umin));
9968
9969 /* Calculate bulk Richardson number... */
9970 const double rib =
9971 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
9972 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
9973 met->h2o[ix][iy][ip]) - tvs) / vh2;
9974
9975 /* Check for critical value... */
9976 if (rib >= rib_crit) {
9977 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
9978 rib, met->p[ip], rib_crit));
9979 if (met->pbl[ix][iy] > pbl_bot)
9980 met->pbl[ix][iy] = (float) pbl_bot;
9981 break;
9982 }
9983
9984 /* Save Richardson number... */
9985 rib_old = rib;
9986 }
9987 }
9988 }
9989
9990 /* Determine PBL based on potential temperature... */
9991 if (ctl->met_pbl == 3) {
9992
9993 /* Parameters used to estimate the height of the PBL
9994 (following HYSPLIT model)... */
9995 const double dtheta = 2.0, zmin = 0.1;
9996
9997 /* Loop over grid points... */
9998#pragma omp parallel for default(shared) collapse(2)
9999 for (int ix = 0; ix < met->nx; ix++)
10000 for (int iy = 0; iy < met->ny; iy++) {
10001
10002 /* Potential temperature at the surface... */
10003 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
10004
10005 /* Find topmost level where theta exceeds surface value by 2 K... */
10006 int ip;
10007 for (ip = met->np - 2; ip > 0; ip--)
10008 if (met->p[ip] >= 300.)
10009 if (met->p[ip] > met->ps[ix][iy]
10010 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
10011 break;
10012
10013 /* Interpolate... */
10014 met->pbl[ix][iy]
10015 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
10016 met->p[ip + 1],
10017 THETA(met->p[ip], met->t[ix][iy][ip]),
10018 met->p[ip], theta0 + dtheta));
10019
10020 /* Check minimum value... */
10021 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
10022 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
10023 met->pbl[ix][iy] = (float) pbl_min;
10024 }
10025 }
10026
10027 /* Loop over grid points... */
10028#pragma omp parallel for default(shared) collapse(2)
10029 for (int ix = 0; ix < met->nx; ix++)
10030 for (int iy = 0; iy < met->ny; iy++) {
10031
10032 /* Check minimum value... */
10033 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
10034 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
10035
10036 /* Check maximum value... */
10037 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
10038 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
10039 }
10040}
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 10044 of file mptrac.c.

10045 {
10046
10047 /* Set timer... */
10048 SELECT_TIMER("READ_MET_PERIODIC", "METPROC");
10049 LOG(2, "Apply periodic boundary conditions...");
10050
10051 /* Check longitudes... */
10052 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
10053 + met->lon[1] - met->lon[0] - 360) < 0.01))
10054 return;
10055
10056 /* Increase longitude counter... */
10057 if ((++met->nx) >= EX)
10058 ERRMSG("Cannot create periodic boundary conditions!");
10059
10060 /* Set longitude... */
10061 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
10062
10063 /* Loop over latitudes and pressure levels... */
10064#pragma omp parallel for default(shared)
10065 for (int iy = 0; iy < met->ny; iy++) {
10066 met->ps[met->nx - 1][iy] = met->ps[0][iy];
10067 met->zs[met->nx - 1][iy] = met->zs[0][iy];
10068 met->ts[met->nx - 1][iy] = met->ts[0][iy];
10069 met->us[met->nx - 1][iy] = met->us[0][iy];
10070 met->vs[met->nx - 1][iy] = met->vs[0][iy];
10071 met->ess[met->nx - 1][iy] = met->ess[0][iy];
10072 met->nss[met->nx - 1][iy] = met->nss[0][iy];
10073 met->shf[met->nx - 1][iy] = met->shf[0][iy];
10074 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
10075 met->sst[met->nx - 1][iy] = met->sst[0][iy];
10076 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
10077 met->cape[met->nx - 1][iy] = met->cape[0][iy];
10078 met->cin[met->nx - 1][iy] = met->cin[0][iy];
10079 for (int ip = 0; ip < met->np; ip++) {
10080 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
10081 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
10082 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
10083 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
10084 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
10085 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
10086 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
10087 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
10088 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
10089 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
10090 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
10091 }
10092 for (int ip = 0; ip < met->npl; ip++) {
10093 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
10094 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
10095 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
10096 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
10097 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
10098 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
10099 }
10100 }
10101}

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

10106 {
10107
10108 /* Set timer... */
10109 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC");
10110 LOG(2, "Apply fix for polar winds...");
10111
10112 /* Check latitudes... */
10113 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
10114 return;
10115
10116 /* Loop over hemispheres... */
10117 for (int ihem = 0; ihem < 2; ihem++) {
10118
10119 /* Set latitude indices... */
10120 int i89 = 1, i90 = 0, sign = 1;
10121 if (ihem == 1) {
10122 i89 = met->ny - 2;
10123 i90 = met->ny - 1;
10124 }
10125 if (met->lat[i90] < 0)
10126 sign = -1;
10127
10128 /* Look-up table of cosinus and sinus... */
10129 double clon[EX], slon[EX];
10130#pragma omp parallel for default(shared)
10131 for (int ix = 0; ix < met->nx; ix++) {
10132 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
10133 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
10134 }
10135
10136 /* Loop over levels... */
10137#pragma omp parallel for default(shared)
10138 for (int ip = 0; ip < met->np; ip++) {
10139
10140 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
10141 double vel89x = 0, vel89y = 0;
10142 for (int ix = 0; ix < met->nx; ix++) {
10143 vel89x +=
10144 (met->u[ix][i89][ip] * clon[ix] -
10145 met->v[ix][i89][ip] * slon[ix]) / met->nx;
10146 vel89y +=
10147 (met->u[ix][i89][ip] * slon[ix] +
10148 met->v[ix][i89][ip] * clon[ix]) / met->nx;
10149 }
10150
10151 /* Replace 90 degree winds by 89 degree mean... */
10152 for (int ix = 0; ix < met->nx; ix++) {
10153 met->u[ix][i90][ip]
10154 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
10155 met->v[ix][i90][ip]
10156 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
10157 }
10158 }
10159 }
10160}

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

10165 {
10166
10167 double pows[EP];
10168
10169 /* Set timer... */
10170 SELECT_TIMER("READ_MET_PV", "METPROC");
10171 LOG(2, "Calculate potential vorticity...");
10172
10173 /* Set powers... */
10174#pragma omp parallel for default(shared)
10175 for (int ip = 0; ip < met->np; ip++)
10176 pows[ip] = pow(1000. / met->p[ip], 0.286);
10177
10178 /* Loop over grid points... */
10179#pragma omp parallel for default(shared)
10180 for (int ix = 0; ix < met->nx; ix++) {
10181
10182 /* Set indices... */
10183 const int ix0 = MAX(ix - 1, 0);
10184 const int ix1 = MIN(ix + 1, met->nx - 1);
10185
10186 /* Loop over grid points... */
10187 for (int iy = 0; iy < met->ny; iy++) {
10188
10189 /* Set indices... */
10190 const int iy0 = MAX(iy - 1, 0);
10191 const int iy1 = MIN(iy + 1, met->ny - 1);
10192
10193 /* Set auxiliary variables... */
10194 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
10195 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
10196 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
10197 const double c0 = cos(DEG2RAD(met->lat[iy0]));
10198 const double c1 = cos(DEG2RAD(met->lat[iy1]));
10199 const double cr = cos(DEG2RAD(latr));
10200 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
10201
10202 /* Loop over grid points... */
10203 for (int ip = 0; ip < met->np; ip++) {
10204
10205 /* Get gradients in longitude... */
10206 const double dtdx
10207 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
10208 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
10209
10210 /* Get gradients in latitude... */
10211 const double dtdy
10212 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
10213 const double dudy
10214 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
10215
10216 /* Set indices... */
10217 const int ip0 = MAX(ip - 1, 0);
10218 const int ip1 = MIN(ip + 1, met->np - 1);
10219
10220 /* Get gradients in pressure... */
10221 double dtdp, dudp, dvdp;
10222 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
10223 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
10224 if (ip != ip0 && ip != ip1) {
10225 double denom = dp0 * dp1 * (dp0 + dp1);
10226 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
10227 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
10228 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
10229 / denom;
10230 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
10231 - dp1 * dp1 * met->u[ix][iy][ip0]
10232 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
10233 / denom;
10234 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
10235 - dp1 * dp1 * met->v[ix][iy][ip0]
10236 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
10237 / denom;
10238 } else {
10239 const double denom = dp0 + dp1;
10240 dtdp =
10241 (met->t[ix][iy][ip1] * pows[ip1] -
10242 met->t[ix][iy][ip0] * pows[ip0]) / denom;
10243 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
10244 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
10245 }
10246
10247 /* Calculate PV... */
10248 met->pv[ix][iy][ip] = (float)
10249 (1e6 * G0 *
10250 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
10251 }
10252 }
10253 }
10254
10255 /* Fix for polar regions... */
10256#pragma omp parallel for default(shared)
10257 for (int ix = 0; ix < met->nx; ix++)
10258 for (int ip = 0; ip < met->np; ip++) {
10259 met->pv[ix][0][ip]
10260 = met->pv[ix][1][ip]
10261 = met->pv[ix][2][ip];
10262 met->pv[ix][met->ny - 1][ip]
10263 = met->pv[ix][met->ny - 2][ip]
10264 = met->pv[ix][met->ny - 3][ip];
10265 }
10266}
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:587
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:566

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

10271 {
10272
10273 /* Set timer... */
10274 SELECT_TIMER("READ_MET_OZONE", "METPROC");
10275 LOG(2, "Calculate total column ozone...");
10276
10277 /* Loop over columns... */
10278#pragma omp parallel for default(shared) collapse(2)
10279 for (int ix = 0; ix < met->nx; ix++)
10280 for (int iy = 0; iy < met->ny; iy++) {
10281
10282 /* Integrate... */
10283 double cd = 0;
10284 for (int ip = 1; ip < met->np; ip++)
10285 if (met->p[ip - 1] <= met->ps[ix][iy]) {
10286 const double vmr =
10287 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
10288 const double dp = met->p[ip - 1] - met->p[ip];
10289 cd += vmr * MO3 / MA * dp * 1e2 / G0;
10290 }
10291
10292 /* Convert to Dobson units... */
10293 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
10294 }
10295}

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

10301 {
10302
10303 met_t *help;
10304
10305 /* Check parameters... */
10306 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
10307 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
10308 return;
10309
10310 /* Set timer... */
10311 SELECT_TIMER("READ_MET_SAMPLE", "METPROC");
10312 LOG(2, "Downsampling of meteo data...");
10313
10314 /* Allocate... */
10315 ALLOC(help, met_t, 1);
10316
10317 /* Copy data... */
10318 help->nx = met->nx;
10319 help->ny = met->ny;
10320 help->np = met->np;
10321 memcpy(help->lon, met->lon, sizeof(met->lon));
10322 memcpy(help->lat, met->lat, sizeof(met->lat));
10323 memcpy(help->p, met->p, sizeof(met->p));
10324
10325 /* Smoothing... */
10326 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
10327 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
10328 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
10329 help->ps[ix][iy] = 0;
10330 help->zs[ix][iy] = 0;
10331 help->ts[ix][iy] = 0;
10332 help->us[ix][iy] = 0;
10333 help->vs[ix][iy] = 0;
10334 help->ess[ix][iy] = 0;
10335 help->nss[ix][iy] = 0;
10336 help->shf[ix][iy] = 0;
10337 help->lsm[ix][iy] = 0;
10338 help->sst[ix][iy] = 0;
10339 help->pbl[ix][iy] = 0;
10340 help->cape[ix][iy] = 0;
10341 help->cin[ix][iy] = 0;
10342 help->t[ix][iy][ip] = 0;
10343 help->u[ix][iy][ip] = 0;
10344 help->v[ix][iy][ip] = 0;
10345 help->w[ix][iy][ip] = 0;
10346 help->h2o[ix][iy][ip] = 0;
10347 help->o3[ix][iy][ip] = 0;
10348 help->lwc[ix][iy][ip] = 0;
10349 help->rwc[ix][iy][ip] = 0;
10350 help->iwc[ix][iy][ip] = 0;
10351 help->swc[ix][iy][ip] = 0;
10352 help->cc[ix][iy][ip] = 0;
10353 float wsum = 0;
10354 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
10355 ix2++) {
10356 int ix3 = ix2;
10357 if (ix3 < 0)
10358 ix3 += met->nx;
10359 else if (ix3 >= met->nx)
10360 ix3 -= met->nx;
10361
10362 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
10363 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
10364 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
10365 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
10366 const float w =
10367 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
10368 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
10369 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
10370 help->ps[ix][iy] += w * met->ps[ix3][iy2];
10371 help->zs[ix][iy] += w * met->zs[ix3][iy2];
10372 help->ts[ix][iy] += w * met->ts[ix3][iy2];
10373 help->us[ix][iy] += w * met->us[ix3][iy2];
10374 help->vs[ix][iy] += w * met->vs[ix3][iy2];
10375 help->ess[ix][iy] += w * met->ess[ix3][iy2];
10376 help->nss[ix][iy] += w * met->nss[ix3][iy2];
10377 help->shf[ix][iy] += w * met->shf[ix3][iy2];
10378 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
10379 help->sst[ix][iy] += w * met->sst[ix3][iy2];
10380 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
10381 help->cape[ix][iy] += w * met->cape[ix3][iy2];
10382 help->cin[ix][iy] += w * met->cin[ix3][iy2];
10383 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
10384 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
10385 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
10386 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
10387 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
10388 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
10389 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
10390 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
10391 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
10392 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
10393 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
10394 wsum += w;
10395 }
10396 }
10397 help->ps[ix][iy] /= wsum;
10398 help->zs[ix][iy] /= wsum;
10399 help->ts[ix][iy] /= wsum;
10400 help->us[ix][iy] /= wsum;
10401 help->vs[ix][iy] /= wsum;
10402 help->ess[ix][iy] /= wsum;
10403 help->nss[ix][iy] /= wsum;
10404 help->shf[ix][iy] /= wsum;
10405 help->lsm[ix][iy] /= wsum;
10406 help->sst[ix][iy] /= wsum;
10407 help->pbl[ix][iy] /= wsum;
10408 help->cape[ix][iy] /= wsum;
10409 help->cin[ix][iy] /= wsum;
10410 help->t[ix][iy][ip] /= wsum;
10411 help->u[ix][iy][ip] /= wsum;
10412 help->v[ix][iy][ip] /= wsum;
10413 help->w[ix][iy][ip] /= wsum;
10414 help->h2o[ix][iy][ip] /= wsum;
10415 help->o3[ix][iy][ip] /= wsum;
10416 help->lwc[ix][iy][ip] /= wsum;
10417 help->rwc[ix][iy][ip] /= wsum;
10418 help->iwc[ix][iy][ip] /= wsum;
10419 help->swc[ix][iy][ip] /= wsum;
10420 help->cc[ix][iy][ip] /= wsum;
10421 }
10422 }
10423 }
10424
10425 /* Downsampling... */
10426 met->nx = 0;
10427 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
10428 met->lon[met->nx] = help->lon[ix];
10429 met->ny = 0;
10430 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
10431 met->lat[met->ny] = help->lat[iy];
10432 met->ps[met->nx][met->ny] = help->ps[ix][iy];
10433 met->zs[met->nx][met->ny] = help->zs[ix][iy];
10434 met->ts[met->nx][met->ny] = help->ts[ix][iy];
10435 met->us[met->nx][met->ny] = help->us[ix][iy];
10436 met->vs[met->nx][met->ny] = help->vs[ix][iy];
10437 met->ess[met->nx][met->ny] = help->ess[ix][iy];
10438 met->nss[met->nx][met->ny] = help->nss[ix][iy];
10439 met->shf[met->nx][met->ny] = help->shf[ix][iy];
10440 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
10441 met->sst[met->nx][met->ny] = help->sst[ix][iy];
10442 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
10443 met->cape[met->nx][met->ny] = help->cape[ix][iy];
10444 met->cin[met->nx][met->ny] = help->cin[ix][iy];
10445 met->np = 0;
10446 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
10447 met->p[met->np] = help->p[ip];
10448 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
10449 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
10450 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
10451 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
10452 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
10453 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
10454 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
10455 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
10456 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
10457 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
10458 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
10459 met->np++;
10460 }
10461 met->ny++;
10462 }
10463 met->nx++;
10464 }
10465
10466 /* Free... */
10467 free(help);
10468}

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

10475 {
10476
10477 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
10478 th2[200], z[EP], z2[200];
10479
10480 /* Set timer... */
10481 SELECT_TIMER("READ_MET_TROPO", "METPROC");
10482 LOG(2, "Calculate tropopause...");
10483
10484 /* Get altitude and pressure profiles... */
10485#pragma omp parallel for default(shared)
10486 for (int iz = 0; iz < met->np; iz++)
10487 z[iz] = Z(met->p[iz]);
10488#pragma omp parallel for default(shared)
10489 for (int iz = 0; iz <= 190; iz++) {
10490 z2[iz] = 4.5 + 0.1 * iz;
10491 p2[iz] = P(z2[iz]);
10492 }
10493
10494 /* Do not calculate tropopause... */
10495 if (ctl->met_tropo == 0)
10496#pragma omp parallel for default(shared) collapse(2)
10497 for (int ix = 0; ix < met->nx; ix++)
10498 for (int iy = 0; iy < met->ny; iy++)
10499 met->pt[ix][iy] = NAN;
10500
10501 /* Use tropopause climatology... */
10502 else if (ctl->met_tropo == 1) {
10503#pragma omp parallel for default(shared) collapse(2)
10504 for (int ix = 0; ix < met->nx; ix++)
10505 for (int iy = 0; iy < met->ny; iy++)
10506 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
10507 }
10508
10509 /* Use cold point... */
10510 else if (ctl->met_tropo == 2) {
10511
10512 /* Loop over grid points... */
10513#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10514 for (int ix = 0; ix < met->nx; ix++)
10515 for (int iy = 0; iy < met->ny; iy++) {
10516
10517 /* Interpolate temperature profile... */
10518 for (int iz = 0; iz < met->np; iz++)
10519 t[iz] = met->t[ix][iy][iz];
10520 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
10521
10522 /* Find minimum... */
10523 int iz = (int) gsl_stats_min_index(t2, 1, 171);
10524 if (iz > 0 && iz < 170)
10525 met->pt[ix][iy] = (float) p2[iz];
10526 else
10527 met->pt[ix][iy] = NAN;
10528 }
10529 }
10530
10531 /* Use WMO definition... */
10532 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
10533
10534 /* Loop over grid points... */
10535#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10536 for (int ix = 0; ix < met->nx; ix++)
10537 for (int iy = 0; iy < met->ny; iy++) {
10538
10539 /* Interpolate temperature profile... */
10540 int iz;
10541 for (iz = 0; iz < met->np; iz++)
10542 t[iz] = met->t[ix][iy][iz];
10543 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
10544
10545 /* Find 1st tropopause... */
10546 met->pt[ix][iy] = NAN;
10547 for (iz = 0; iz <= 170; iz++) {
10548 int found = 1;
10549 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10550 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10551 found = 0;
10552 break;
10553 }
10554 if (found) {
10555 if (iz > 0 && iz < 170)
10556 met->pt[ix][iy] = (float) p2[iz];
10557 break;
10558 }
10559 }
10560
10561 /* Find 2nd tropopause... */
10562 if (ctl->met_tropo == 4) {
10563 met->pt[ix][iy] = NAN;
10564 for (; iz <= 170; iz++) {
10565 int found = 1;
10566 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
10567 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
10568 found = 0;
10569 break;
10570 }
10571 if (found)
10572 break;
10573 }
10574 for (; iz <= 170; iz++) {
10575 int found = 1;
10576 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10577 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10578 found = 0;
10579 break;
10580 }
10581 if (found) {
10582 if (iz > 0 && iz < 170)
10583 met->pt[ix][iy] = (float) p2[iz];
10584 break;
10585 }
10586 }
10587 }
10588 }
10589 }
10590
10591 /* Use dynamical tropopause... */
10592 else if (ctl->met_tropo == 5) {
10593
10594 /* Loop over grid points... */
10595#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
10596 for (int ix = 0; ix < met->nx; ix++)
10597 for (int iy = 0; iy < met->ny; iy++) {
10598
10599 /* Interpolate potential vorticity profile... */
10600 for (int iz = 0; iz < met->np; iz++)
10601 pv[iz] = met->pv[ix][iy][iz];
10602 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
10603
10604 /* Interpolate potential temperature profile... */
10605 for (int iz = 0; iz < met->np; iz++)
10606 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
10607 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
10608
10609 /* Find dynamical tropopause... */
10610 met->pt[ix][iy] = NAN;
10611 for (int iz = 0; iz <= 170; iz++)
10612 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
10613 || th2[iz] >= ctl->met_tropo_theta) {
10614 if (iz > 0 && iz < 170)
10615 met->pt[ix][iy] = (float) p2[iz];
10616 break;
10617 }
10618 }
10619 }
10620
10621 else
10622 ERRMSG("Cannot calculate tropopause!");
10623
10624 /* Interpolate temperature, geopotential height, and water vapor... */
10625#pragma omp parallel for default(shared) collapse(2)
10626 for (int ix = 0; ix < met->nx; ix++)
10627 for (int iy = 0; iy < met->ny; iy++) {
10628 double h2ot, tt, zt;
10630 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
10631 met->lat[iy], &tt, ci, cw, 1);
10632 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
10633 met->lat[iy], &zt, ci, cw, 0);
10634 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
10635 met->lat[iy], &h2ot, ci, cw, 0);
10636 met->tt[ix][iy] = (float) tt;
10637 met->zt[ix][iy] = (float) zt;
10638 met->h2ot[ix][iy] = (float) h2ot;
10639 }
10640}
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:10850
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:1028
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 10644 of file mptrac.c.

10652 {
10653
10654 /* Write info... */
10655 LOG(1, "Read observation data: %s", filename);
10656
10657 /* Read data... */
10658 if (ctl->obs_type == 0)
10659 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
10660 else if (ctl->obs_type == 1)
10661 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
10662 else
10663 ERRMSG("Set OBS_TYPE to 0 or 1!");
10664
10665 /* Check time... */
10666 for (int i = 1; i < *nobs; i++)
10667 if (rt[i] < rt[i - 1])
10668 ERRMSG("Time must be ascending!");
10669
10670 /* Write info... */
10671 int n = *nobs;
10672 double mini, maxi;
10673 LOG(2, "Number of observations: %d", *nobs);
10674 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
10675 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
10676 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
10677 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
10678 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
10679 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
10680 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
10681 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
10682 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
10683 LOG(2, "Observation range: %g ... %g", mini, maxi);
10684}
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:10688
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:10716
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 10688 of file mptrac.c.

10695 {
10696
10697 /* Open observation data file... */
10698 FILE *in;
10699 if (!(in = fopen(filename, "r")))
10700 ERRMSG("Cannot open file!");
10701
10702 /* Read observations... */
10703 char line[LEN];
10704 while (fgets(line, LEN, in))
10705 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
10706 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
10707 if ((++(*nobs)) >= NOBS)
10708 ERRMSG("Too many observations!");
10709
10710 /* Close observation data file... */
10711 fclose(in);
10712}
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:375

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

10723 {
10724
10725 int ncid, varid;
10726
10727 /* Open netCDF file... */
10728 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
10729 ERRMSG("Cannot open file!");
10730
10731 /* Read the observations from the NetCDF file... */
10732 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
10733 NC_GET_DOUBLE("time", rt, 1);
10734 NC_GET_DOUBLE("alt", rz, 1);
10735 NC_GET_DOUBLE("lon", rlon, 1);
10736 NC_GET_DOUBLE("lat", rlat, 1);
10737 NC_GET_DOUBLE("obs", robs, 1);
10738
10739 /* Close file... */
10740 NC(nc_close(ncid));
10741}

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

10752 {
10753
10754 FILE *in = NULL;
10755
10756 char fullname1[LEN], fullname2[LEN], rval[LEN];
10757
10758 int contain = 0, i;
10759
10760 /* Open file... */
10761 if (filename[strlen(filename) - 1] != '-')
10762 if (!(in = fopen(filename, "r")))
10763 ERRMSG("Cannot open file!");
10764
10765 /* Set full variable name... */
10766 if (arridx >= 0) {
10767 sprintf(fullname1, "%s[%d]", varname, arridx);
10768 sprintf(fullname2, "%s[*]", varname);
10769 } else {
10770 sprintf(fullname1, "%s", varname);
10771 sprintf(fullname2, "%s", varname);
10772 }
10773
10774 /* Read data... */
10775 if (in != NULL) {
10776 char dummy[LEN], line[LEN], rvarname[LEN];
10777 while (fgets(line, LEN, in)) {
10778 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
10779 if (strcasecmp(rvarname, fullname1) == 0 ||
10780 strcasecmp(rvarname, fullname2) == 0) {
10781 contain = 1;
10782 break;
10783 }
10784 }
10785 }
10786 for (i = 1; i < argc - 1; i++)
10787 if (strcasecmp(argv[i], fullname1) == 0 ||
10788 strcasecmp(argv[i], fullname2) == 0) {
10789 sprintf(rval, "%s", argv[i + 1]);
10790 contain = 1;
10791 break;
10792 }
10793
10794 /* Close file... */
10795 if (in != NULL)
10796 fclose(in);
10797
10798 /* Check for missing variables... */
10799 if (!contain) {
10800 if (strlen(defvalue) > 0)
10801 sprintf(rval, "%s", defvalue);
10802 else
10803 ERRMSG("Missing variable %s!\n", fullname1);
10804 }
10805
10806 /* Write info... */
10807 LOG(1, "%s = %s", fullname1, rval);
10808
10809 /* Return values... */
10810 if (value != NULL)
10811 sprintf(value, "%s", rval);
10812 return atof(rval);
10813}

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

10821 {
10822
10823 /* Convert particle radius from microns to m... */
10824 const double rp_help = rp * 1e-6;
10825
10826 /* Density of dry air [kg / m^3]... */
10827 const double rho = RHO(p, T);
10828
10829 /* Dynamic viscosity of air [kg / (m s)]... */
10830 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
10831
10832 /* Thermal velocity of an air molecule [m / s]... */
10833 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
10834
10835 /* Mean free path of an air molecule [m]... */
10836 const double lambda = 2. * eta / (rho * v);
10837
10838 /* Knudsen number for air (dimensionless)... */
10839 const double K = lambda / rp_help;
10840
10841 /* Cunningham slip-flow correction (dimensionless)... */
10842 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
10843
10844 /* Sedimentation velocity [m / s]... */
10845 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
10846}
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:281

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

10857 {
10858
10859 /* Cubic spline interpolation... */
10860 if (method == 1) {
10861
10862 /* Allocate... */
10863 gsl_interp_accel *acc = gsl_interp_accel_alloc();
10864 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
10865
10866 /* Interpolate profile... */
10867 gsl_spline_init(s, x, y, (size_t) n);
10868 for (int i = 0; i < n2; i++)
10869 if (x2[i] <= x[0])
10870 y2[i] = y[0];
10871 else if (x2[i] >= x[n - 1])
10872 y2[i] = y[n - 1];
10873 else
10874 y2[i] = gsl_spline_eval(s, x2[i], acc);
10875
10876 /* Free... */
10877 gsl_spline_free(s);
10878 gsl_interp_accel_free(acc);
10879 }
10880
10881 /* Linear interpolation... */
10882 else {
10883 for (int i = 0; i < n2; i++)
10884 if (x2[i] <= x[0])
10885 y2[i] = y[0];
10886 else if (x2[i] >= x[n - 1])
10887 y2[i] = y[n - 1];
10888 else {
10889 const int idx = locate_irr(x, n, x2[i]);
10890 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
10891 }
10892 }
10893}
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 10897 of file mptrac.c.

10899 {
10900
10901 if (n <= 0)
10902 return 0;
10903
10904 float mean = 0, var = 0;
10905
10906 for (int i = 0; i < n; ++i) {
10907 mean += data[i];
10908 var += SQR(data[i]);
10909 }
10910
10911 var = var / (float) n - SQR(mean / (float) n);
10912
10913 return (var > 0 ? sqrtf(var) : 0);
10914}

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

10926 {
10927
10928 struct tm t0, t1;
10929
10930 t0.tm_year = 100;
10931 t0.tm_mon = 0;
10932 t0.tm_mday = 1;
10933 t0.tm_hour = 0;
10934 t0.tm_min = 0;
10935 t0.tm_sec = 0;
10936
10937 t1.tm_year = year - 1900;
10938 t1.tm_mon = mon - 1;
10939 t1.tm_mday = day;
10940 t1.tm_hour = hour;
10941 t1.tm_min = min;
10942 t1.tm_sec = sec;
10943
10944 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
10945}

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

10952 {
10953
10954 static char names[NTIMER][100], groups[NTIMER][100];
10955
10956 static double rt_name[NTIMER], rt_group[NTIMER],
10957 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
10958
10959 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
10960
10961 /* Get time... */
10962 t1 = omp_get_wtime();
10963 dt = t1 - t0;
10964
10965 /* Add elapsed time to current timers... */
10966 if (iname >= 0) {
10967 rt_name[iname] += dt;
10968 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
10969 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
10970 ct_name[iname]++;
10971 }
10972 if (igroup >= 0)
10973 rt_group[igroup] += t1 - t0;
10974
10975 /* Report timers... */
10976 if (output) {
10977 for (int i = 0; i < nname; i++)
10978 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
10979 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
10980 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
10981 for (int i = 0; i < ngroup; i++)
10982 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
10983 double total = 0.0;
10984 for (int i = 0; i < nname; i++)
10985 total += rt_name[i];
10986 LOG(1, "TIMER_TOTAL = %.3f s", total);
10987 }
10988
10989 /* Identify IDs of next timer... */
10990 for (iname = 0; iname < nname; iname++)
10991 if (strcasecmp(name, names[iname]) == 0)
10992 break;
10993 for (igroup = 0; igroup < ngroup; igroup++)
10994 if (strcasecmp(group, groups[igroup]) == 0)
10995 break;
10996
10997 /* Check whether this is a new timer... */
10998 if (iname >= nname) {
10999 sprintf(names[iname], "%s", name);
11000 if ((++nname) >= NTIMER)
11001 ERRMSG("Too many timers!");
11002 }
11003
11004 /* Check whether this is a new group... */
11005 if (igroup >= ngroup) {
11006 sprintf(groups[igroup], "%s", group);
11007 if ((++ngroup) >= NTIMER)
11008 ERRMSG("Too many groups!");
11009 }
11010
11011 /* Save starting time... */
11012 t0 = t1;
11013}
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2146

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

11019 {
11020
11021 char tstr[10];
11022
11023 double t;
11024
11025 /* Get time from filename... */
11026 int len = (int) strlen(filename);
11027 sprintf(tstr, "%.4s", &filename[len - offset]);
11028 int year = atoi(tstr);
11029 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
11030 int mon = atoi(tstr);
11031 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
11032 int day = atoi(tstr);
11033 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
11034 int hour = atoi(tstr);
11035 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
11036 int min = atoi(tstr);
11037
11038 /* Check time... */
11039 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
11040 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
11041 ERRMSG("Cannot read time from filename!");
11042
11043 /* Convert time to Julian seconds... */
11044 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
11045
11046 /* Return time... */
11047 return t;
11048}
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 11052 of file mptrac.c.

11055 {
11056
11057 /* Get tropopause pressure... */
11058 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
11059
11060 /* Get pressure range... */
11061 const double p1 = pt * 0.866877899;
11062 const double p0 = pt / 0.866877899;
11063
11064 /* Get weighting factor... */
11065 if (atm->p[ip] > p0)
11066 return 1;
11067 else if (atm->p[ip] < p1)
11068 return 0;
11069 else
11070 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
11071}
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 11075 of file mptrac.c.

11079 {
11080
11081 FILE *out;
11082
11083 /* Set time interval for output... */
11084 const double t0 = t - 0.5 * ctl->dt_mod;
11085 const double t1 = t + 0.5 * ctl->dt_mod;
11086
11087 /* Check if gnuplot output is requested... */
11088 if (ctl->atm_gpfile[0] != '-') {
11089
11090 /* Create gnuplot pipe... */
11091 if (!(out = popen("gnuplot", "w")))
11092 ERRMSG("Cannot create pipe to gnuplot!");
11093
11094 /* Set plot filename... */
11095 fprintf(out, "set out \"%s.png\"\n", filename);
11096
11097 /* Set time string... */
11098 double r;
11099 int year, mon, day, hour, min, sec;
11100 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11101 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
11102 year, mon, day, hour, min);
11103
11104 /* Dump gnuplot file to pipe... */
11105 FILE *in;
11106 if (!(in = fopen(ctl->atm_gpfile, "r")))
11107 ERRMSG("Cannot open file!");
11108 char line[LEN];
11109 while (fgets(line, LEN, in))
11110 fprintf(out, "%s", line);
11111 fclose(in);
11112 }
11113
11114 else {
11115
11116 /* Create file... */
11117 if (!(out = fopen(filename, "w")))
11118 ERRMSG("Cannot create file!");
11119 }
11120
11121 /* Write header... */
11122 fprintf(out,
11123 "# $1 = time [s]\n"
11124 "# $2 = altitude [km]\n"
11125 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11126 for (int iq = 0; iq < ctl->nq; iq++)
11127 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
11128 ctl->qnt_unit[iq]);
11129 fprintf(out, "\n");
11130
11131 /* Write data... */
11132 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
11133
11134 /* Check time... */
11135 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11136 continue;
11137
11138 /* Write output... */
11139 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
11140 atm->lon[ip], atm->lat[ip]);
11141 for (int iq = 0; iq < ctl->nq; iq++) {
11142 fprintf(out, " ");
11143 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11144 fprintf(out, ctl->qnt_format[iq], NAN);
11145 else
11146 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11147 }
11148 fprintf(out, "\n");
11149 }
11150
11151 /* Close file... */
11152 fclose(out);
11153}
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 11157 of file mptrac.c.

11160 {
11161
11162 FILE *out;
11163
11164 /* Create file... */
11165 if (!(out = fopen(filename, "w")))
11166 ERRMSG("Cannot create file!");
11167
11168 /* Write version of binary data... */
11169 int version = 100;
11170 FWRITE(&version, int,
11171 1,
11172 out);
11173
11174 /* Write data... */
11175 FWRITE(&atm->np, int,
11176 1,
11177 out);
11178 FWRITE(atm->time, double,
11179 (size_t) atm->np,
11180 out);
11181 FWRITE(atm->p, double,
11182 (size_t) atm->np,
11183 out);
11184 FWRITE(atm->lon, double,
11185 (size_t) atm->np,
11186 out);
11187 FWRITE(atm->lat, double,
11188 (size_t) atm->np,
11189 out);
11190 for (int iq = 0; iq < ctl->nq; iq++)
11191 FWRITE(atm->q[iq], double,
11192 (size_t) atm->np,
11193 out);
11194
11195 /* Write final flag... */
11196 int final = 999;
11197 FWRITE(&final, int,
11198 1,
11199 out);
11200
11201 /* Close file... */
11202 fclose(out);
11203}

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

11210 {
11211
11212 int tid, pid, ncid, varid;
11213 size_t start[2], count[2];
11214
11215 /* Create file... */
11216 NC(nc_create(filename, NC_NETCDF4, &ncid));
11217
11218 /* Define dimensions... */
11219 NC(nc_def_dim(ncid, "time", 1, &tid));
11220 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11221
11222 /* Define variables and their attributes... */
11223 int dim_ids[2] = { tid, pid };
11224 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11225 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11226 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11227 ctl->atm_nc_level, 0);
11228 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11229 ctl->atm_nc_level, 0);
11230 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11231 ctl->atm_nc_level, 0);
11232 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11233 for (int iq = 0; iq < ctl->nq; iq++)
11234 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11235 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11236 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11237
11238 /* Define global attributes... */
11239 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11240 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11241
11242 /* End definitions... */
11243 NC(nc_enddef(ncid));
11244
11245 /* Write data... */
11246 NC_PUT_DOUBLE("time", atm->time, 0);
11247 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11248 NC_PUT_DOUBLE("LON", atm->lon, 0);
11249 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11250 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11251 for (int iq = 0; iq < ctl->nq; iq++)
11252 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11253
11254 /* Close file... */
11255 NC(nc_close(ncid));
11256}
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1403
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1233
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1317

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

11264 {
11265
11266 /* Global Counter... */
11267 static size_t out_cnt = 0;
11268
11269 double r, r_start, r_stop;
11270 int year, mon, day, hour, min, sec;
11271 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
11272 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
11273 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
11274
11275 int ncid, varid, tid, pid, cid;
11276 int dim_ids[2];
11277
11278 /* time, nparc */
11279 size_t start[2];
11280 size_t count[2];
11281
11282 /* Determine start and stop times of calculation... */
11283 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11284 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
11285 &min_start, &sec_start, &r_start);
11286 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
11287 &min_stop, &sec_stop, &r_stop);
11288
11289 sprintf(filename_out,
11290 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
11291 year_start % 100, mon_start, day_start, hour_start,
11292 year_stop % 100, mon_stop, day_stop, hour_stop);
11293 LOG(1, "Write traj file: %s", filename_out);
11294
11295 /* Define hyperslap for the traj_file... */
11296 start[0] = out_cnt;
11297 start[1] = 0;
11298 count[0] = 1;
11299 count[1] = (size_t) atm->np;
11300
11301 /* Create the file at the first timestep... */
11302 if (out_cnt == 0) {
11303
11304 /* Create file... */
11305 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
11306
11307 /* Define dimensions... */
11308 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
11309 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11310 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
11311 dim_ids[0] = tid;
11312 dim_ids[1] = pid;
11313
11314 /* Define variables and their attributes... */
11315 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11316 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11317 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
11318 ctl->atm_nc_level, 0);
11319 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
11320 ctl->atm_nc_level, 0);
11321 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
11322 ctl->atm_nc_level, 0);
11323 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
11324 ctl->atm_nc_level, 0);
11325 for (int iq = 0; iq < ctl->nq; iq++)
11326 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11327 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11328 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11329
11330 /* Define global attributes... */
11331 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11332 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11333
11334 /* End definitions... */
11335 NC(nc_enddef(ncid));
11336 NC(nc_close(ncid));
11337 }
11338
11339 /* Increment global counter to change hyperslap... */
11340 out_cnt++;
11341
11342 /* Open file... */
11343 NC(nc_open(filename_out, NC_WRITE, &ncid));
11344
11345 /* Write data... */
11346 NC_PUT_DOUBLE("time", atm->time, 1);
11347 NC_PUT_DOUBLE("LAT", atm->lat, 1);
11348 NC_PUT_DOUBLE("LON", atm->lon, 1);
11349 NC_PUT_DOUBLE("PRESS", atm->p, 1);
11350 if (ctl->advect_vert_coord == 1) {
11351 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
11352 } else if (ctl->qnt_zeta >= 0) {
11353 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
11354 }
11355 for (int iq = 0; iq < ctl->nq; iq++)
11356 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
11357
11358 /* Close file... */
11359 NC(nc_close(ncid));
11360
11361 /* At the last time step create the init_fix_YYYYMMDDHH file... */
11362 if ((year == year_stop) && (mon == mon_stop)
11363 && (day == day_stop) && (hour == hour_stop)) {
11364
11365 /* Set filename... */
11366 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
11367 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
11368 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
11369 LOG(1, "Write init file: %s", filename_init);
11370
11371 /* Create file... */
11372 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
11373
11374 /* Define dimensions... */
11375 NC(nc_def_dim(ncid, "time", 1, &tid));
11376 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11377 dim_ids[0] = tid;
11378 dim_ids[1] = pid;
11379
11380 /* Define variables and their attributes... */
11381 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11382 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11383 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11384 ctl->atm_nc_level, 0);
11385 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11386 ctl->atm_nc_level, 0);
11387 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11388 ctl->atm_nc_level, 0);
11389 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11390 for (int iq = 0; iq < ctl->nq; iq++)
11391 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11392 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11393 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11394
11395 /* Define global attributes... */
11396 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11397 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11398
11399 /* End definitions... */
11400 NC(nc_enddef(ncid));
11401
11402 /* Write data... */
11403 NC_PUT_DOUBLE("time", atm->time, 0);
11404 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11405 NC_PUT_DOUBLE("LON", atm->lon, 0);
11406 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11407 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11408 for (int iq = 0; iq < ctl->nq; iq++)
11409 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11410
11411 /* Close file... */
11412 NC(nc_close(ncid));
11413 }
11414}
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 11418 of file mptrac.c.

11421 {
11422
11423 int ncid, obsid, varid;
11424
11425 size_t start[2], count[2];
11426
11427 /* Create file... */
11428 NC(nc_create(filename, NC_NETCDF4, &ncid));
11429
11430 /* Define dimensions... */
11431 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
11432
11433 /* Define variables and their attributes... */
11434 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
11435 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11436 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
11437 ctl->atm_nc_level, 0);
11438 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
11439 ctl->atm_nc_level, 0);
11440 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
11441 ctl->atm_nc_level, 0);
11442 for (int iq = 0; iq < ctl->nq; iq++)
11443 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
11444 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
11445 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11446
11447 /* Define global attributes... */
11448 NC_PUT_ATT_GLOBAL("featureType", "point");
11449
11450 /* End definitions... */
11451 NC(nc_enddef(ncid));
11452
11453 /* Write data... */
11454 NC_PUT_DOUBLE("time", atm->time, 0);
11455 NC_PUT_DOUBLE("press", atm->p, 0);
11456 NC_PUT_DOUBLE("lon", atm->lon, 0);
11457 NC_PUT_DOUBLE("lat", atm->lat, 0);
11458 for (int iq = 0; iq < ctl->nq; iq++)
11459 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11460
11461 /* Close file... */
11462 NC(nc_close(ncid));
11463}

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

11471 {
11472
11473 static FILE *out;
11474
11475 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
11476 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
11477
11478 static int *obscount, nobs, nk;
11479
11480 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
11481
11482 const int ensemble = (ctl->nens > 0);
11483
11484 /* Set timer */
11485 SELECT_TIMER("WRITE_CSI", "OUTPUT");
11486
11487 /* Check quantities... */
11488 if (ctl->qnt_m < 0)
11489 ERRMSG("Need quantity mass!");
11490 if (ensemble) {
11491 if (ctl->qnt_ens < 0)
11492 ERRMSG("Missing ensemble IDs!");
11493 if (ctl->nens > NENS)
11494 ERRMSG("Too many ensembles!");
11495 }
11496
11497 /* Init... */
11498 if (t == ctl->t_start) {
11499
11500 /* Allocate.. */
11501 ALLOC(area, double,
11502 ctl->csi_ny);
11503 ALLOC(rt, double,
11504 NOBS);
11505 ALLOC(rz, double,
11506 NOBS);
11507 ALLOC(rlon, double,
11508 NOBS);
11509 ALLOC(rlat, double,
11510 NOBS);
11511 ALLOC(robs, double,
11512 NOBS);
11513
11514 /* Read observation data... */
11515 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11516
11517 /* Read kernel data... */
11518 if (ctl->csi_kernel[0] != '-')
11519 read_kernel(ctl->csi_kernel, kz, kw, &nk);
11520
11521 /* Create new file... */
11522 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
11523 if (!(out = fopen(filename, "w")))
11524 ERRMSG("Cannot create file!");
11525
11526 /* Write header... */
11527 fprintf(out,
11528 "# $1 = time [s]\n"
11529 "# $2 = ensemble ID\n"
11530 "# $3 = number of hits (cx)\n"
11531 "# $4 = number of misses (cy)\n"
11532 "# $5 = number of false alarms (cz)\n"
11533 "# $6 = number of observations (cx + cy)\n"
11534 "# $7 = number of forecasts (cx + cz)\n"
11535 "# $8 = bias (%%)\n"
11536 "# $9 = POD (%%)\n"
11537 "# $10 = FAR (%%)\n"
11538 "# $11 = CSI (%%)\n"
11539 "# $12 = hits by random chance\n"
11540 "# $13 = ETS (%%)\n"
11541 "# $14 = Pearson R\n"
11542 "# $15 = Spearman R\n"
11543 "# $16 = mean error [kg/m²]\n"
11544 "# $17 = RMSE [kg/m²]\n"
11545 "# $18 = MAE [kg/m²]\n"
11546 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
11547
11548 /* Set grid box size... */
11549 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
11550 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
11551 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
11552
11553 /* Set horizontal coordinates... */
11554 for (int iy = 0; iy < ctl->csi_ny; iy++) {
11555 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
11556 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
11557 }
11558 }
11559
11560 /* Set time interval... */
11561 const double t0 = t - 0.5 * ctl->dt_mod;
11562 const double t1 = t + 0.5 * ctl->dt_mod;
11563
11564 /* Allocate... */
11565 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
11566 ALLOC(modmean, double,
11567 (ensemble ? ctl->nens : 1) * grid_size);
11568 ALLOC(obsmean, double,
11569 grid_size);
11570 ALLOC(obscount, int,
11571 grid_size);
11572 ALLOC(obsstd, double,
11573 grid_size);
11574
11575 /* Init... */
11576 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
11577 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
11578
11579 /* Loop over observations... */
11580 for (int i = 0; i < nobs; i++) {
11581 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
11582 continue;
11583
11584 /* Calculate indices... */
11585 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
11586 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
11587 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
11588 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11589 || iz >= ctl->csi_nz)
11590 continue;
11591
11592 /* Get mean observation index... */
11593 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11594 obsmean[idx] += robs[i];
11595 obsstd[idx] += SQR(robs[i]);
11596 obscount[idx]++;
11597 }
11598
11599 /* Analyze model data... */
11600 for (int ip = 0; ip < atm->np; ip++) {
11601
11602 /* Check time... */
11603 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11604 continue;
11605
11606 /* Get ensemble ID... */
11607 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
11608 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
11609 ERRMSG("Ensemble ID out of range!");
11610
11611 /* Get indices... */
11612 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
11613 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
11614 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
11615 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11616 || iz >= ctl->csi_nz)
11617 continue;
11618
11619 /* Get total mass in grid cell... */
11620 const int idx =
11621 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11622 modmean[idx] +=
11623 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11624 }
11625 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11626 /* Analyze all grid cells... */
11627 for (int ix = 0; ix < ctl->csi_nx; ix++)
11628 for (int iy = 0; iy < ctl->csi_ny; iy++)
11629 for (int iz = 0; iz < ctl->csi_nz; iz++) {
11630
11631 /* Calculate mean observation index... */
11632 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11633 if (e == 0)
11634 if (obscount[idx]) {
11635 obsmean[idx] /= obscount[idx];
11636 obsstd[idx] =
11637 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
11638 }
11639
11640 /* Calculate model mean per ensemble... */
11641 const int midx = e * grid_size + idx;
11642 if (modmean[midx] > 0)
11643 modmean[midx] /= (1e6 * area[iy]);
11644
11645 /* Check number of observations... */
11646 if (obscount[idx]) {
11647
11648 /* Calculate CSI... */
11649 ct[e]++;
11650 if (obsmean[idx] >= ctl->csi_obsmin
11651 && modmean[midx] >= ctl->csi_modmin)
11652 cx[e]++;
11653 else if (obsmean[idx] >= ctl->csi_obsmin)
11654 cy[e]++;
11655 else if (modmean[midx] >= ctl->csi_modmin)
11656 cz[e]++;
11657
11658 /* Save data for other verification statistics... */
11659 if (obsmean[idx] >= ctl->csi_obsmin
11660 || modmean[midx] >= ctl->csi_modmin) {
11661 x[n[e]] = modmean[midx];
11662 y[n[e]] = obsmean[idx];
11663 if (modmean[midx] >= ctl->csi_modmin)
11664 obsstdn[n[e]] = obsstd[idx];
11665 if ((++n[e]) >= NCSI)
11666 ERRMSG("Too many points for statistics!");
11667 }
11668 }
11669 }
11670 /* Write output... */
11671 if (fmod(t, ctl->csi_dt_out) == 0) {
11672
11673 if (n[e] == 0)
11674 continue;
11675
11676 /* Calculate verification statistics
11677 (https://www.cawcr.gov.au/projects/verification/) ... */
11678 static double work[2 * NCSI], work2[2 * NCSI];
11679 const int n_obs = cx[e] + cy[e];
11680 const int n_for = cx[e] + cz[e];
11681 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
11682 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
11683 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
11684 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
11685 const double csi =
11686 (cx[e] + cy[e] + cz[e] >
11687 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
11688 const double ets =
11689 (cx[e] + cy[e] + cz[e] - cx_rd >
11690 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
11691 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
11692 const double rho_s =
11693 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
11694 for (int i = 0; i < n[e]; i++) {
11695 work[i] = x[i] - y[i];
11696 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
11697 }
11698 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
11699 const double rmse =
11700 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
11701 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
11702 const double loglikelihood =
11703 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
11704
11705 /* Write... */
11706 fprintf(out,
11707 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
11708 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
11709 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
11710 loglikelihood, n[e]);
11711
11712 /* Set counters to zero... */
11713 for (int i = 0; i < n[e]; i++)
11714 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
11715 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
11716 }
11717 }
11718 /* Free... */
11719 free(modmean);
11720 free(obsmean);
11721 free(obscount);
11722 free(obsstd);
11723
11724 /* Finalize... */
11725 if (t == ctl->t_stop) {
11726
11727 /* Close output file... */
11728 fclose(out);
11729
11730 /* Free... */
11731 free(area);
11732 free(rt);
11733 free(rz);
11734 free(rlon);
11735 free(rlat);
11736 free(robs);
11737 }
11738}
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:10644
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:7230
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:2327
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:370
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:365
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 11742 of file mptrac.c.

11746 {
11747
11748 static FILE *out;
11749
11750 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
11751 x[3], zm[NENS];
11752
11753 static int n[NENS];
11754
11755 /* Set timer... */
11756 SELECT_TIMER("WRITE_ENS", "OUTPUT");
11757
11758 /* Check quantities... */
11759 if (ctl->qnt_ens < 0)
11760 ERRMSG("Missing ensemble IDs!");
11761
11762 /* Set time interval... */
11763 const double t0 = t - 0.5 * ctl->dt_mod;
11764 const double t1 = t + 0.5 * ctl->dt_mod;
11765
11766 /* Init... */
11767 for (int i = 0; i < NENS; i++) {
11768 for (int iq = 0; iq < ctl->nq; iq++)
11769 qm[iq][i] = qs[iq][i] = 0;
11770 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
11771 n[i] = 0;
11772 }
11773
11774 /* Loop over air parcels... */
11775 for (int ip = 0; ip < atm->np; ip++) {
11776
11777 /* Check time... */
11778 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11779 continue;
11780
11781 /* Check ensemble ID... */
11782 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
11783 ERRMSG("Ensemble ID is out of range!");
11784
11785 /* Get means... */
11786 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
11787 for (int iq = 0; iq < ctl->nq; iq++) {
11788 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
11789 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
11790 }
11791 xm[ctl->qnt_ens][0] += x[0];
11792 xm[ctl->qnt_ens][1] += x[1];
11793 xm[ctl->qnt_ens][2] += x[2];
11794 zm[ctl->qnt_ens] += Z(atm->p[ip]);
11795 n[ctl->qnt_ens]++;
11796 }
11797
11798 /* Create file... */
11799 LOG(1, "Write ensemble data: %s", filename);
11800 if (!(out = fopen(filename, "w")))
11801 ERRMSG("Cannot create file!");
11802
11803 /* Write header... */
11804 fprintf(out,
11805 "# $1 = time [s]\n"
11806 "# $2 = altitude [km]\n"
11807 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11808 for (int iq = 0; iq < ctl->nq; iq++)
11809 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
11810 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11811 for (int iq = 0; iq < ctl->nq; iq++)
11812 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
11813 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11814 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
11815
11816 /* Write data... */
11817 for (int i = 0; i < NENS; i++)
11818 if (n[i] > 0) {
11819 cart2geo(xm[i], &dummy, &lon, &lat);
11820 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
11821 for (int iq = 0; iq < ctl->nq; iq++) {
11822 fprintf(out, " ");
11823 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
11824 }
11825 for (int iq = 0; iq < ctl->nq; iq++) {
11826 fprintf(out, " ");
11827 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
11828 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
11829 }
11830 fprintf(out, " %d\n", n[i]);
11831 }
11832
11833 /* Close file... */
11834 fclose(out);
11835}
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
Here is the call graph for this function:

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

11845 {
11846
11847 static double kz[EP], kw[EP];
11848
11849 static int nk;
11850
11851 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
11852
11853 int *ixs, *iys, *izs, *np;
11854
11855 /* Set timer... */
11856 SELECT_TIMER("WRITE_GRID", "OUTPUT");
11857
11858 /* Write info... */
11859 LOG(1, "Write grid data: %s", filename);
11860
11861 /* Init... */
11862 if (t == ctl->t_start) {
11863
11864 /* Read kernel data... */
11865 if (ctl->grid_kernel[0] != '-')
11866 read_kernel(ctl->grid_kernel, kz, kw, &nk);
11867 }
11868
11869 /* Allocate... */
11870 ALLOC(cd, double,
11871 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11872 for (int iq = 0; iq < ctl->nq; iq++) {
11873 ALLOC(mean[iq], double,
11874 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11875 ALLOC(sigma[iq], double,
11876 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11877 }
11878 ALLOC(vmr_impl, double,
11879 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11880 ALLOC(z, double,
11881 ctl->grid_nz);
11882 ALLOC(lon, double,
11883 ctl->grid_nx);
11884 ALLOC(lat, double,
11885 ctl->grid_ny);
11886 ALLOC(area, double,
11887 ctl->grid_ny);
11888 ALLOC(press, double,
11889 ctl->grid_nz);
11890 ALLOC(np, int,
11891 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11892 ALLOC(ixs, int,
11893 atm->np);
11894 ALLOC(iys, int,
11895 atm->np);
11896 ALLOC(izs, int,
11897 atm->np);
11898
11899 /* Set grid box size... */
11900 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
11901 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
11902 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
11903
11904 /* Set vertical coordinates... */
11905#pragma omp parallel for default(shared)
11906 for (int iz = 0; iz < ctl->grid_nz; iz++) {
11907 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
11908 press[iz] = P(z[iz]);
11909 }
11910
11911 /* Set horizontal coordinates... */
11912 for (int ix = 0; ix < ctl->grid_nx; ix++)
11913 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
11914#pragma omp parallel for default(shared)
11915 for (int iy = 0; iy < ctl->grid_ny; iy++) {
11916 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
11917 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
11918 }
11919
11920 /* Set time interval for output... */
11921 const double t0 = t - 0.5 * ctl->dt_mod;
11922 const double t1 = t + 0.5 * ctl->dt_mod;
11923
11924 /* Get grid box indices... */
11925#pragma omp parallel for default(shared)
11926 for (int ip = 0; ip < atm->np; ip++) {
11927 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
11928 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
11929 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
11930 if (atm->time[ip] < t0 || atm->time[ip] > t1
11931 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
11932 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
11933 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
11934 izs[ip] = -1;
11935 }
11936
11937 /* Average data... */
11938 for (int ip = 0; ip < atm->np; ip++)
11939 if (izs[ip] >= 0) {
11940 const int idx =
11941 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
11942 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
11943 np[idx]++;
11944 for (int iq = 0; iq < ctl->nq; iq++) {
11945 mean[iq][idx] += kernel * atm->q[iq][ip];
11946 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
11947 }
11948 }
11949
11950 /* Calculate column density and volume mixing ratio... */
11951#pragma omp parallel for default(shared)
11952 for (int ix = 0; ix < ctl->grid_nx; ix++)
11953 for (int iy = 0; iy < ctl->grid_ny; iy++)
11954 for (int iz = 0; iz < ctl->grid_nz; iz++) {
11955
11956 /* Get grid index... */
11957 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
11958
11959 /* Calculate column density... */
11960 cd[idx] = NAN;
11961 if (ctl->qnt_m >= 0)
11962 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
11963
11964 /* Calculate volume mixing ratio (implicit)... */
11965 vmr_impl[idx] = NAN;
11966 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
11967 && met1 != NULL) {
11968 vmr_impl[idx] = 0;
11969 if (mean[ctl->qnt_m][idx] > 0) {
11970
11971 /* Get temperature... */
11972 double temp;
11974 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
11975 lon[ix], lat[iy], &temp, ci, cw, 1);
11976
11977 /* Calculate volume mixing ratio... */
11978 vmr_impl[idx] =
11979 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
11980 }
11981 }
11982
11983 /* Calculate mean... */
11984 if (np[idx] > 0)
11985 for (int iq = 0; iq < ctl->nq; iq++) {
11986 mean[iq][idx] /= np[idx];
11987 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
11988 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
11989 } else
11990 for (int iq = 0; iq < ctl->nq; iq++) {
11991 mean[iq][idx] = NAN;
11992 sigma[iq][idx] = NAN;
11993 }
11994 }
11995
11996 /* Write ASCII data... */
11997 if (ctl->grid_type == 0)
11998 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
11999 t, z, lon, lat, area, dz, np);
12000
12001 /* Write netCDF data... */
12002 else if (ctl->grid_type == 1)
12003 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
12004 t, z, lon, lat, area, dz, np);
12005
12006 /* Error message... */
12007 else
12008 ERRMSG("Grid data format GRID_TYPE unknown!");
12009
12010 /* Free... */
12011 free(cd);
12012 for (int iq = 0; iq < ctl->nq; iq++) {
12013 free(mean[iq]);
12014 free(sigma[iq]);
12015 }
12016 free(vmr_impl);
12017 free(z);
12018 free(lon);
12019 free(lat);
12020 free(area);
12021 free(press);
12022 free(np);
12023 free(ixs);
12024 free(iys);
12025 free(izs);
12026}
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:12030
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:12134
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 12030 of file mptrac.c.

12043 {
12044
12045 FILE *out;
12046
12047 /* Check if gnuplot output is requested... */
12048 if (ctl->grid_gpfile[0] != '-') {
12049
12050 /* Create gnuplot pipe... */
12051 if (!(out = popen("gnuplot", "w")))
12052 ERRMSG("Cannot create pipe to gnuplot!");
12053
12054 /* Set plot filename... */
12055 fprintf(out, "set out \"%s.png\"\n", filename);
12056
12057 /* Set time string... */
12058 double r;
12059 int year, mon, day, hour, min, sec;
12060 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12061 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12062 year, mon, day, hour, min);
12063
12064 /* Dump gnuplot file to pipe... */
12065 FILE *in;
12066 char line[LEN];
12067 if (!(in = fopen(ctl->grid_gpfile, "r")))
12068 ERRMSG("Cannot open file!");
12069 while (fgets(line, LEN, in))
12070 fprintf(out, "%s", line);
12071 fclose(in);
12072 }
12073
12074 else {
12075
12076 /* Create file... */
12077 if (!(out = fopen(filename, "w")))
12078 ERRMSG("Cannot create file!");
12079 }
12080
12081 /* Write header... */
12082 fprintf(out,
12083 "# $1 = time [s]\n"
12084 "# $2 = altitude [km]\n"
12085 "# $3 = longitude [deg]\n"
12086 "# $4 = latitude [deg]\n"
12087 "# $5 = surface area [km^2]\n"
12088 "# $6 = layer depth [km]\n"
12089 "# $7 = column density (implicit) [kg/m^2]\n"
12090 "# $8 = volume mixing ratio (implicit) [ppv]\n"
12091 "# $9 = number of particles [1]\n");
12092 for (int iq = 0; iq < ctl->nq; iq++)
12093 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
12094 ctl->qnt_unit[iq]);
12095 if (ctl->grid_stddev)
12096 for (int iq = 0; iq < ctl->nq; iq++)
12097 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
12098 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12099 fprintf(out, "\n");
12100
12101 /* Write data... */
12102 for (int ix = 0; ix < ctl->grid_nx; ix++) {
12103 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
12104 fprintf(out, "\n");
12105 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12106 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
12107 fprintf(out, "\n");
12108 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12109 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12110 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
12111 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
12112 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
12113 for (int iq = 0; iq < ctl->nq; iq++) {
12114 fprintf(out, " ");
12115 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
12116 }
12117 if (ctl->grid_stddev)
12118 for (int iq = 0; iq < ctl->nq; iq++) {
12119 fprintf(out, " ");
12120 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
12121 }
12122 fprintf(out, "\n");
12123 }
12124 }
12125 }
12126 }
12127
12128 /* Close file... */
12129 fclose(out);
12130}
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 12134 of file mptrac.c.

12147 {
12148
12149 char longname[2 * LEN], varname[2 * LEN];
12150
12151 double *help;
12152
12153 int *help2, ncid, dimid[10], varid;
12154
12155 size_t start[2], count[2];
12156
12157 /* Allocate... */
12158 ALLOC(help, double,
12159 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12160 ALLOC(help2, int,
12161 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12162
12163 /* Create file... */
12164 NC(nc_create(filename, NC_NETCDF4, &ncid));
12165
12166 /* Define dimensions... */
12167 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
12168 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
12169 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
12170 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
12171 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
12172
12173 /* Define variables and their attributes... */
12174 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
12175 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12176 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
12177 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
12178 0);
12179 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
12180 0);
12181 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
12182 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
12183
12184 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
12185 ctl->grid_nc_level, 0);
12186 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
12187 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
12188 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
12189 for (int iq = 0; iq < ctl->nq; iq++) {
12190 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12191 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
12192 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12193 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12194 if (ctl->grid_stddev) {
12195 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12196 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
12197 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12198 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12199 }
12200 }
12201 /* End definitions... */
12202 NC(nc_enddef(ncid));
12203
12204 /* Write data... */
12205 NC_PUT_DOUBLE("time", &t, 0);
12206 NC_PUT_DOUBLE("lon", lon, 0);
12207 NC_PUT_DOUBLE("lat", lat, 0);
12208 NC_PUT_DOUBLE("z", z, 0);
12209 NC_PUT_DOUBLE("area", area, 0);
12210 NC_PUT_DOUBLE("dz", &dz, 0);
12211
12212 for (int ix = 0; ix < ctl->grid_nx; ix++)
12213 for (int iy = 0; iy < ctl->grid_ny; iy++)
12214 for (int iz = 0; iz < ctl->grid_nz; iz++)
12215 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12216 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12217 NC_PUT_DOUBLE("cd", help, 0);
12218
12219 for (int ix = 0; ix < ctl->grid_nx; ix++)
12220 for (int iy = 0; iy < ctl->grid_ny; iy++)
12221 for (int iz = 0; iz < ctl->grid_nz; iz++)
12222 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12223 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12224 NC_PUT_DOUBLE("vmr_impl", help, 0);
12225
12226 for (int ix = 0; ix < ctl->grid_nx; ix++)
12227 for (int iy = 0; iy < ctl->grid_ny; iy++)
12228 for (int iz = 0; iz < ctl->grid_nz; iz++)
12229 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12230 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12231 NC_PUT_INT("np", help2, 0);
12232
12233 for (int iq = 0; iq < ctl->nq; iq++) {
12234 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12235 for (int ix = 0; ix < ctl->grid_nx; ix++)
12236 for (int iy = 0; iy < ctl->grid_ny; iy++)
12237 for (int iz = 0; iz < ctl->grid_nz; iz++)
12238 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12239 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12240 NC_PUT_DOUBLE(varname, help, 0);
12241 }
12242
12243 if (ctl->grid_stddev)
12244 for (int iq = 0; iq < ctl->nq; iq++) {
12245 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12246 for (int ix = 0; ix < ctl->grid_nx; ix++)
12247 for (int iy = 0; iy < ctl->grid_ny; iy++)
12248 for (int iz = 0; iz < ctl->grid_nz; iz++)
12249 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12250 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12251 NC_PUT_DOUBLE(varname, help, 0);
12252 }
12253
12254 /* Close file... */
12255 NC(nc_close(ncid));
12256
12257 /* Free... */
12258 free(help);
12259 free(help2);
12260}
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1364

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

12267 {
12268
12269 /* Create file... */
12270 FILE *out;
12271 if (!(out = fopen(filename, "w")))
12272 ERRMSG("Cannot create file!");
12273
12274 /* Write type of binary data... */
12275 FWRITE(&ctl->met_type, int,
12276 1,
12277 out);
12278
12279 /* Write version of binary data... */
12280 int version = 103;
12281 FWRITE(&version, int,
12282 1,
12283 out);
12284
12285 /* Write grid data... */
12286 FWRITE(&met->time, double,
12287 1,
12288 out);
12289 FWRITE(&met->nx, int,
12290 1,
12291 out);
12292 FWRITE(&met->ny, int,
12293 1,
12294 out);
12295 FWRITE(&met->np, int,
12296 1,
12297 out);
12298 FWRITE(met->lon, double,
12299 (size_t) met->nx,
12300 out);
12301 FWRITE(met->lat, double,
12302 (size_t) met->ny,
12303 out);
12304 FWRITE(met->p, double,
12305 (size_t) met->np,
12306 out);
12307
12308 /* Write surface data... */
12309 write_met_bin_2d(out, met, met->ps, "PS");
12310 write_met_bin_2d(out, met, met->ts, "TS");
12311 write_met_bin_2d(out, met, met->zs, "ZS");
12312 write_met_bin_2d(out, met, met->us, "US");
12313 write_met_bin_2d(out, met, met->vs, "VS");
12314 write_met_bin_2d(out, met, met->ess, "ESS");
12315 write_met_bin_2d(out, met, met->nss, "NSS");
12316 write_met_bin_2d(out, met, met->shf, "SHF");
12317 write_met_bin_2d(out, met, met->lsm, "LSM");
12318 write_met_bin_2d(out, met, met->sst, "SST");
12319 write_met_bin_2d(out, met, met->pbl, "PBL");
12320 write_met_bin_2d(out, met, met->pt, "PT");
12321 write_met_bin_2d(out, met, met->tt, "TT");
12322 write_met_bin_2d(out, met, met->zt, "ZT");
12323 write_met_bin_2d(out, met, met->h2ot, "H2OT");
12324 write_met_bin_2d(out, met, met->pct, "PCT");
12325 write_met_bin_2d(out, met, met->pcb, "PCB");
12326 write_met_bin_2d(out, met, met->cl, "CL");
12327 write_met_bin_2d(out, met, met->plcl, "PLCL");
12328 write_met_bin_2d(out, met, met->plfc, "PLFC");
12329 write_met_bin_2d(out, met, met->pel, "PEL");
12330 write_met_bin_2d(out, met, met->cape, "CAPE");
12331 write_met_bin_2d(out, met, met->cin, "CIN");
12332 write_met_bin_2d(out, met, met->o3c, "O3C");
12333
12334 /* Write level data... */
12335 write_met_bin_3d(out, ctl, met, met->z, "Z",
12336 ctl->met_comp_prec[0], ctl->met_comp_tol[0]);
12337 write_met_bin_3d(out, ctl, met, met->t, "T",
12338 ctl->met_comp_prec[1], ctl->met_comp_tol[1]);
12339 write_met_bin_3d(out, ctl, met, met->u, "U",
12340 ctl->met_comp_prec[2], ctl->met_comp_tol[2]);
12341 write_met_bin_3d(out, ctl, met, met->v, "V",
12342 ctl->met_comp_prec[3], ctl->met_comp_tol[3]);
12343 write_met_bin_3d(out, ctl, met, met->w, "W",
12344 ctl->met_comp_prec[4], ctl->met_comp_tol[4]);
12345 write_met_bin_3d(out, ctl, met, met->pv, "PV",
12346 ctl->met_comp_prec[5], ctl->met_comp_tol[5]);
12347 write_met_bin_3d(out, ctl, met, met->h2o, "H2O",
12348 ctl->met_comp_prec[6], ctl->met_comp_tol[6]);
12349 write_met_bin_3d(out, ctl, met, met->o3, "O3",
12350 ctl->met_comp_prec[7], ctl->met_comp_tol[7]);
12351 write_met_bin_3d(out, ctl, met, met->lwc, "LWC",
12352 ctl->met_comp_prec[8], ctl->met_comp_tol[8]);
12353 write_met_bin_3d(out, ctl, met, met->rwc, "RWC",
12354 ctl->met_comp_prec[9], ctl->met_comp_tol[9]);
12355 write_met_bin_3d(out, ctl, met, met->iwc, "IWC",
12356 ctl->met_comp_prec[10], ctl->met_comp_tol[10]);
12357 write_met_bin_3d(out, ctl, met, met->swc, "SWC",
12358 ctl->met_comp_prec[11], ctl->met_comp_tol[11]);
12359 write_met_bin_3d(out, ctl, met, met->cc, "CC",
12360 ctl->met_comp_prec[12], ctl->met_comp_tol[12]);
12361 if (METVAR != 13)
12362 ERRMSG("Number of meteo variables doesn't match!");
12363
12364 /* Write final flag... */
12365 int final = 999;
12366 FWRITE(&final, int,
12367 1,
12368 out);
12369
12370 /* Close file... */
12371 fclose(out);
12372}
void write_met_bin_3d(FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int precision, const double tolerance)
Writes a 3-dimensional meteorological variable to a binary file.
Definition: mptrac.c:12405
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:12376
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 12376 of file mptrac.c.

12380 {
12381
12382 float *help;
12383
12384 /* Allocate... */
12385 ALLOC(help, float,
12386 EX * EY);
12387
12388 /* Copy data... */
12389 for (int ix = 0; ix < met->nx; ix++)
12390 for (int iy = 0; iy < met->ny; iy++)
12391 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
12392
12393 /* Write uncompressed data... */
12394 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
12395 FWRITE(help, float,
12396 (size_t) (met->nx * met->ny),
12397 out);
12398
12399 /* Free... */
12400 free(help);
12401}

◆ 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  precision,
const double  tolerance 
)

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.
precisionAn integer specifying the precision of compression (for certain compression methods).
toleranceA double specifying the tolerance for compression (for certain compression methods).

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

12412 {
12413
12414 float *help;
12415
12416 /* Allocate... */
12417 ALLOC(help, float,
12418 EX * EY * EP);
12419
12420 /* Copy data... */
12421#pragma omp parallel for default(shared) collapse(2)
12422 for (int ix = 0; ix < met->nx; ix++)
12423 for (int iy = 0; iy < met->ny; iy++)
12424 for (int ip = 0; ip < met->np; ip++)
12425 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
12426
12427 /* Write uncompressed data... */
12428 if (ctl->met_type == 1) {
12429 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
12430 FWRITE(help, float,
12431 (size_t) (met->nx * met->ny * met->np),
12432 out);
12433 }
12434
12435 /* Write packed data... */
12436 else if (ctl->met_type == 2)
12437 compress_pck(varname, help, (size_t) (met->ny * met->nx),
12438 (size_t) met->np, 0, out);
12439
12440 /* Write ZFP data... */
12441#ifdef ZFP
12442 else if (ctl->met_type == 3) {
12443 FWRITE(&precision, int,
12444 1,
12445 out);
12446 FWRITE(&tolerance, double,
12447 1,
12448 out);
12449 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
12450 tolerance, 0, out);
12451 }
12452#endif
12453
12454 /* Write zstd data... */
12455#ifdef ZSTD
12456 else if (ctl->met_type == 4)
12457 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
12458 ctl->met_zstd_level, out);
12459#endif
12460
12461 /* Write cmultiscale data... */
12462#ifdef CMS
12463 else if (ctl->met_type == 5) {
12464 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
12465 (size_t) met->np, met->p, 0, out);
12466 }
12467#endif
12468
12469 /* Write SZ3 data... */
12470#ifdef SZ3
12471 else if (ctl->met_type == 7) {
12472 FWRITE(&precision, int,
12473 1,
12474 out);
12475 FWRITE(&tolerance, double,
12476 1,
12477 out);
12478 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
12479 tolerance, 0, out);
12480 }
12481#endif
12482
12483 /* Unknown method... */
12484 else {
12485 ERRMSG("MET_TYPE not supported!");
12486
12487 /* This will never execute, hack to avoid compilation error... */
12488 LOG(3, "%d %g", precision, tolerance);
12489 }
12490
12491 /* Free... */
12492 free(help);
12493}
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 12497 of file mptrac.c.

12500 {
12501
12502 /* Create file... */
12503 int ncid, varid;
12504 size_t start[4], count[4];
12505 NC(nc_create(filename, NC_NETCDF4, &ncid));
12506
12507 /* Define dimensions... */
12508 int tid, lonid, latid, levid;
12509 NC(nc_def_dim(ncid, "time", 1, &tid));
12510 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
12511 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
12512 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
12513
12514 /* Define grid... */
12515 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
12516 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12517 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
12518 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
12519 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
12520
12521 /* Define surface variables... */
12522 int dimid2[2] = { latid, lonid };
12523 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
12524 ctl->met_nc_level, 0);
12525 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
12526 ctl->met_nc_level, 0);
12527 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
12528 ctl->met_nc_level, 0);
12529 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
12530 "m s**-1", ctl->met_nc_level, 0);
12531 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
12532 "m s**-1", ctl->met_nc_level, 0);
12533 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
12534 "Instantaneous eastward turbulent surface stress", "N m**-2",
12535 ctl->met_nc_level, 0);
12536 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
12537 "Instantaneous northward turbulent surface stress", "N m**-2",
12538 ctl->met_nc_level, 0);
12539 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
12540 "Instantaneous surface sensible heat flux", "W m**-1",
12541 ctl->met_nc_level, 0);
12542 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
12543 ctl->met_nc_level, 0);
12544 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
12545 ctl->met_nc_level, 0);
12546 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
12547 ctl->met_nc_level, 0);
12548 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
12549 ctl->met_nc_level, 0);
12550 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
12551 ctl->met_nc_level, 0);
12552 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
12553 ctl->met_nc_level, 0);
12554 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
12555 ctl->met_nc_level, 0);
12556 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
12557 ctl->met_nc_level, 0);
12558 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
12559 ctl->met_nc_level, 0);
12560 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
12561 "kg m**2", ctl->met_nc_level, 0);
12562 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
12563 "Pressure at lifted condensation level (LCL)", "Pa",
12564 ctl->met_nc_level, 0);
12565 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
12566 "Pressure at level of free convection (LFC)", "Pa",
12567 ctl->met_nc_level, 0);
12568 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
12569 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
12570 0);
12571 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
12572 "Convective available potential energy", "J kg**-1",
12573 ctl->met_nc_level, 0);
12574 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
12575 "J kg**-1", ctl->met_nc_level, 0);
12576 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
12577 ctl->met_nc_level, 0);
12578
12579 /* Define level data... */
12580 int dimid3[3] = { levid, latid, lonid };
12581 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
12582 ctl->met_nc_level, ctl->met_nc_quant);
12583 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
12584 ctl->met_nc_level, ctl->met_nc_quant);
12585 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
12586 ctl->met_nc_level, ctl->met_nc_quant);
12587 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
12588 ctl->met_nc_level, ctl->met_nc_quant);
12589 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
12590 ctl->met_nc_level, ctl->met_nc_quant);
12591 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
12592 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12593 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
12594 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12595 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
12596 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12597 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
12598 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12599 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
12600 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12601 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
12602 ctl->met_nc_level, ctl->met_nc_quant);
12603
12604 /* End definitions... */
12605 NC(nc_enddef(ncid));
12606
12607 /* Write grid data... */
12608 NC_PUT_DOUBLE("time", &met->time, 0);
12609 NC_PUT_DOUBLE("lon", met->lon, 0);
12610 NC_PUT_DOUBLE("lat", met->lat, 0);
12611 double phelp[EP];
12612 for (int ip = 0; ip < met->np; ip++)
12613 phelp[ip] = 100. * met->p[ip];
12614 NC_PUT_DOUBLE("lev", phelp, 0);
12615
12616 /* Write surface data... */
12617 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
12618 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
12619 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
12620 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
12621 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
12622 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
12623 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
12624 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
12625 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
12626 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
12627 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
12628 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
12629 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
12630 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
12631 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
12632 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
12633 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
12634 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
12635 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
12636 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
12637 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
12638 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
12639 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
12640 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
12641
12642 /* Write level data... */
12643 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
12644 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
12645 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
12646 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
12647 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
12648 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
12649 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
12650 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
12651 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
12652 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
12653 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
12654
12655 /* Close file... */
12656 NC(nc_close(ncid));
12657}
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:12661
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:12690
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2560
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2557
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 12661 of file mptrac.c.

12666 {
12667
12668 int varid;
12669 size_t start[4], count[4];
12670
12671 /* Allocate... */
12672 float *help;
12673 ALLOC(help, float,
12674 EX * EY);
12675
12676 /* Copy data... */
12677 for (int ix = 0; ix < met->nx; ix++)
12678 for (int iy = 0; iy < met->ny; iy++)
12679 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
12680
12681 /* Write data... */
12682 NC_PUT_FLOAT(varname, help, 0);
12683
12684 /* Free... */
12685 free(help);
12686}
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1341

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

12695 {
12696
12697 int varid;
12698 size_t start[4], count[4];
12699
12700 /* Allocate... */
12701 float *help;
12702 ALLOC(help, float,
12703 EX * EY * EP);
12704
12705 /* Copy data... */
12706 for (int ix = 0; ix < met->nx; ix++)
12707 for (int iy = 0; iy < met->ny; iy++)
12708 for (int ip = 0; ip < met->np; ip++)
12709 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
12710
12711 /* Write data... */
12712 NC_PUT_FLOAT(varname, help, 0);
12713
12714 /* Free... */
12715 free(help);
12716}

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

12726 {
12727
12728 static FILE *out;
12729
12730 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
12731 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
12732
12733 static int nobs, *obscount, ip, okay;
12734
12735 /* Set timer... */
12736 SELECT_TIMER("WRITE_PROF", "OUTPUT");
12737
12738 /* Init... */
12739 if (t == ctl->t_start) {
12740
12741 /* Check quantity index for mass... */
12742 if (ctl->qnt_m < 0)
12743 ERRMSG("Need quantity mass!");
12744
12745 /* Check molar mass... */
12746 if (ctl->molmass <= 0)
12747 ERRMSG("Specify molar mass!");
12748
12749 /* Allocate... */
12750 ALLOC(lon, double,
12751 ctl->prof_nx);
12752 ALLOC(lat, double,
12753 ctl->prof_ny);
12754 ALLOC(area, double,
12755 ctl->prof_ny);
12756 ALLOC(z, double,
12757 ctl->prof_nz);
12758 ALLOC(press, double,
12759 ctl->prof_nz);
12760 ALLOC(rt, double,
12761 NOBS);
12762 ALLOC(rz, double,
12763 NOBS);
12764 ALLOC(rlon, double,
12765 NOBS);
12766 ALLOC(rlat, double,
12767 NOBS);
12768 ALLOC(robs, double,
12769 NOBS);
12770
12771 /* Read observation data... */
12772 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12773
12774 /* Create new output file... */
12775 LOG(1, "Write profile data: %s", filename);
12776 if (!(out = fopen(filename, "w")))
12777 ERRMSG("Cannot create file!");
12778
12779 /* Write header... */
12780 fprintf(out,
12781 "# $1 = time [s]\n"
12782 "# $2 = altitude [km]\n"
12783 "# $3 = longitude [deg]\n"
12784 "# $4 = latitude [deg]\n"
12785 "# $5 = pressure [hPa]\n"
12786 "# $6 = temperature [K]\n"
12787 "# $7 = volume mixing ratio [ppv]\n"
12788 "# $8 = H2O volume mixing ratio [ppv]\n"
12789 "# $9 = O3 volume mixing ratio [ppv]\n"
12790 "# $10 = observed BT index [K]\n"
12791 "# $11 = number of observations\n");
12792
12793 /* Set grid box size... */
12794 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
12795 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
12796 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
12797
12798 /* Set vertical coordinates... */
12799 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12800 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
12801 press[iz] = P(z[iz]);
12802 }
12803
12804 /* Set horizontal coordinates... */
12805 for (int ix = 0; ix < ctl->prof_nx; ix++)
12806 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
12807 for (int iy = 0; iy < ctl->prof_ny; iy++) {
12808 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
12809 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
12810 }
12811 }
12812
12813 /* Set time interval... */
12814 const double t0 = t - 0.5 * ctl->dt_mod;
12815 const double t1 = t + 0.5 * ctl->dt_mod;
12816
12817 /* Allocate... */
12818 ALLOC(mass, double,
12819 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
12820 ALLOC(obsmean, double,
12821 ctl->prof_nx * ctl->prof_ny);
12822 ALLOC(obscount, int,
12823 ctl->prof_nx * ctl->prof_ny);
12824
12825 /* Loop over observations... */
12826 for (int i = 0; i < nobs; i++) {
12827
12828 /* Check time... */
12829 if (rt[i] < t0)
12830 continue;
12831 else if (rt[i] >= t1)
12832 break;
12833
12834 /* Check observation data... */
12835 if (!isfinite(robs[i]))
12836 continue;
12837
12838 /* Calculate indices... */
12839 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
12840 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
12841
12842 /* Check indices... */
12843 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
12844 continue;
12845
12846 /* Get mean observation index... */
12847 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
12848 obsmean[idx] += robs[i];
12849 obscount[idx]++;
12850 }
12851
12852 /* Analyze model data... */
12853 for (ip = 0; ip < atm->np; ip++) {
12854
12855 /* Check time... */
12856 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12857 continue;
12858
12859 /* Get indices... */
12860 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
12861 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
12862 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
12863
12864 /* Check indices... */
12865 if (ix < 0 || ix >= ctl->prof_nx ||
12866 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
12867 continue;
12868
12869 /* Get total mass in grid cell... */
12870 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12871 mass[idx] += atm->q[ctl->qnt_m][ip];
12872 }
12873
12874 /* Extract profiles... */
12875 for (int ix = 0; ix < ctl->prof_nx; ix++)
12876 for (int iy = 0; iy < ctl->prof_ny; iy++) {
12877 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
12878 if (obscount[idx2] > 0) {
12879
12880 /* Check profile... */
12881 okay = 0;
12882 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12883 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12884 if (mass[idx3] > 0) {
12885 okay = 1;
12886 break;
12887 }
12888 }
12889 if (!okay)
12890 continue;
12891
12892 /* Write output... */
12893 fprintf(out, "\n");
12894
12895 /* Loop over altitudes... */
12896 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12897
12898 /* Get temperature, water vapor, and ozone... */
12900 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
12901 lon[ix], lat[iy], &temp, ci, cw, 1);
12902 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
12903 lon[ix], lat[iy], &h2o, ci, cw, 0);
12904 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
12905 lon[ix], lat[iy], &o3, ci, cw, 0);
12906
12907 /* Calculate volume mixing ratio... */
12908 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12909 vmr = MA / ctl->molmass * mass[idx3]
12910 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
12911
12912 /* Write output... */
12913 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
12914 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
12915 obsmean[idx2] / obscount[idx2], obscount[idx2]);
12916 }
12917 }
12918 }
12919
12920 /* Free... */
12921 free(mass);
12922 free(obsmean);
12923 free(obscount);
12924
12925 /* Finalize... */
12926 if (t == ctl->t_stop) {
12927
12928 /* Close output file... */
12929 fclose(out);
12930
12931 /* Free... */
12932 free(lon);
12933 free(lat);
12934 free(area);
12935 free(z);
12936 free(press);
12937 free(rt);
12938 free(rz);
12939 free(rlon);
12940 free(rlat);
12941 free(robs);
12942 }
12943}
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 12947 of file mptrac.c.

12953 {
12954
12955 static FILE *out;
12956
12957 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
12958 kw[EP];
12959
12960 static int nobs, nk;
12961
12962 /* Set timer... */
12963 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT");
12964
12965 /* Init... */
12966 if (t == ctl->t_start) {
12967
12968 /* Allocate... */
12969 ALLOC(rt, double,
12970 NOBS);
12971 ALLOC(rz, double,
12972 NOBS);
12973 ALLOC(rlon, double,
12974 NOBS);
12975 ALLOC(rlat, double,
12976 NOBS);
12977 ALLOC(robs, double,
12978 NOBS);
12979
12980 /* Read observation data... */
12981 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12982
12983 /* Read kernel data... */
12984 if (ctl->sample_kernel[0] != '-')
12985 read_kernel(ctl->sample_kernel, kz, kw, &nk);
12986
12987 /* Create output file... */
12988 LOG(1, "Write sample data: %s", filename);
12989 if (!(out = fopen(filename, "w")))
12990 ERRMSG("Cannot create file!");
12991
12992 /* Write header... */
12993 fprintf(out,
12994 "# $1 = time [s]\n"
12995 "# $2 = altitude [km]\n"
12996 "# $3 = longitude [deg]\n"
12997 "# $4 = latitude [deg]\n"
12998 "# $5 = surface area [km^2]\n"
12999 "# $6 = layer depth [km]\n"
13000 "# $7 = number of particles [1]\n"
13001 "# $8 = column density [kg/m^2]\n"
13002 "# $9 = volume mixing ratio [ppv]\n"
13003 "# $10 = observed BT index [K]\n\n");
13004
13005 /* Set latitude range, squared radius, and area... */
13006 dlat = DY2DEG(ctl->sample_dx);
13007 rmax2 = SQR(ctl->sample_dx);
13008 area = M_PI * rmax2;
13009 }
13010
13011 /* Set time interval for output... */
13012 const double t0 = t - 0.5 * ctl->dt_mod;
13013 const double t1 = t + 0.5 * ctl->dt_mod;
13014
13015 /* Loop over observations... */
13016 for (int i = 0; i < nobs; i++) {
13017
13018 /* Check time... */
13019 if (rt[i] < t0)
13020 continue;
13021 else if (rt[i] >= t1)
13022 break;
13023
13024 /* Calculate Cartesian coordinates... */
13025 double x0[3];
13026 geo2cart(0, rlon[i], rlat[i], x0);
13027
13028 /* Set pressure range... */
13029 const double rp = P(rz[i]);
13030 const double ptop = P(rz[i] + ctl->sample_dz);
13031 const double pbot = P(rz[i] - ctl->sample_dz);
13032
13033 /* Init... */
13034 double mass = 0;
13035 int np = 0;
13036
13037 /* Loop over air parcels... */
13038 //#pragma omp parallel for default(shared) reduction(+:mass,np)
13039 for (int ip = 0; ip < atm->np; ip++) {
13040
13041 /* Check time... */
13042 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13043 continue;
13044
13045 /* Check latitude... */
13046 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
13047 continue;
13048
13049 /* Check horizontal distance... */
13050 double x1[3];
13051 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13052 if (DIST2(x0, x1) > rmax2)
13053 continue;
13054
13055 /* Check pressure... */
13056 if (ctl->sample_dz > 0)
13057 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
13058 continue;
13059
13060 /* Add mass... */
13061 if (ctl->qnt_m >= 0)
13062 mass +=
13063 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13064 np++;
13065 }
13066
13067 /* Calculate column density... */
13068 const double cd = mass / (1e6 * area);
13069
13070 /* Calculate volume mixing ratio... */
13071 double vmr = 0;
13072 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
13073 if (mass > 0) {
13074
13075 /* Get temperature... */
13076 double temp;
13078 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
13079 rlon[i], rlat[i], &temp, ci, cw, 1);
13080
13081 /* Calculate volume mixing ratio... */
13082 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
13083 }
13084 } else
13085 vmr = NAN;
13086
13087 /* Write output... */
13088 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
13089 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
13090 }
13091
13092 /* Finalize...... */
13093 if (t == ctl->t_stop) {
13094
13095 /* Close output file... */
13096 fclose(out);
13097
13098 /* Free... */
13099 free(rt);
13100 free(rz);
13101 free(rlon);
13102 free(rlat);
13103 free(robs);
13104 }
13105}
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 13109 of file mptrac.c.

13113 {
13114
13115 static FILE *out;
13116
13117 static double rmax2, x0[3], x1[3];
13118
13119 /* Set timer... */
13120 SELECT_TIMER("WRITE_STATION", "OUTPUT");
13121
13122 /* Init... */
13123 if (t == ctl->t_start) {
13124
13125 /* Write info... */
13126 LOG(1, "Write station data: %s", filename);
13127
13128 /* Create new file... */
13129 if (!(out = fopen(filename, "w")))
13130 ERRMSG("Cannot create file!");
13131
13132 /* Write header... */
13133 fprintf(out,
13134 "# $1 = time [s]\n"
13135 "# $2 = altitude [km]\n"
13136 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13137 for (int iq = 0; iq < ctl->nq; iq++)
13138 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
13139 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13140 fprintf(out, "\n");
13141
13142 /* Set geolocation and search radius... */
13143 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
13144 rmax2 = SQR(ctl->stat_r);
13145 }
13146
13147 /* Set time interval for output... */
13148 const double t0 = t - 0.5 * ctl->dt_mod;
13149 const double t1 = t + 0.5 * ctl->dt_mod;
13150
13151 /* Loop over air parcels... */
13152 for (int ip = 0; ip < atm->np; ip++) {
13153
13154 /* Check time... */
13155 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13156 continue;
13157
13158 /* Check time range for station output... */
13159 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
13160 continue;
13161
13162 /* Check station flag... */
13163 if (ctl->qnt_stat >= 0)
13164 if ((int) atm->q[ctl->qnt_stat][ip])
13165 continue;
13166
13167 /* Get Cartesian coordinates... */
13168 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13169
13170 /* Check horizontal distance... */
13171 if (DIST2(x0, x1) > rmax2)
13172 continue;
13173
13174 /* Set station flag... */
13175 if (ctl->qnt_stat >= 0)
13176 atm->q[ctl->qnt_stat][ip] = 1;
13177
13178 /* Write data... */
13179 fprintf(out, "%.2f %g %g %g",
13180 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
13181 for (int iq = 0; iq < ctl->nq; iq++) {
13182 fprintf(out, " ");
13183 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
13184 }
13185 fprintf(out, "\n");
13186 }
13187
13188 /* Close file... */
13189 if (t == ctl->t_stop)
13190 fclose(out);
13191}
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 13195 of file mptrac.c.

13199 {
13200
13201 FILE *out;
13202
13203 /* Set timer... */
13204 SELECT_TIMER("WRITE_VTK", "OUTPUT");
13205
13206 /* Write info... */
13207 LOG(1, "Write VTK data: %s", filename);
13208
13209 /* Set time interval for output... */
13210 const double t0 = t - 0.5 * ctl->dt_mod;
13211 const double t1 = t + 0.5 * ctl->dt_mod;
13212
13213 /* Create file... */
13214 if (!(out = fopen(filename, "w")))
13215 ERRMSG("Cannot create file!");
13216
13217 /* Count data points... */
13218 int np = 0;
13219 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13220 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13221 continue;
13222 np++;
13223 }
13224
13225 /* Write header... */
13226 fprintf(out,
13227 "# vtk DataFile Version 3.0\n"
13228 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
13229
13230 /* Write point coordinates... */
13231 fprintf(out, "POINTS %d float\n", np);
13232 if (ctl->vtk_sphere) {
13233 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13234 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13235 continue;
13236 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
13237 + ctl->vtk_offset) / RE;
13238 const double coslat = cos(DEG2RAD(atm->lat[ip]));
13239 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
13240 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
13241 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
13242 fprintf(out, "%g %g %g\n", x, y, z);
13243 }
13244 } else
13245 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13246 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13247 continue;
13248 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
13249 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
13250 }
13251
13252 /* Write point data... */
13253 fprintf(out, "POINT_DATA %d\n", np);
13254 for (int iq = 0; iq < ctl->nq; iq++) {
13255 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
13256 ctl->qnt_name[iq]);
13257 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13258 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13259 continue;
13260 fprintf(out, "%g\n", atm->q[iq][ip]);
13261 }
13262 }
13263
13264 /* Close file... */
13265 fclose(out);
13266}