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_help (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, char *search, char *repl)
 Replaces occurrences of a substring in a string with another substring. More...
 
void get_tropo (const int met_tropo, ctl_t *ctl, 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, 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 data from a NetCDF file and set up subdomain decomposition with halos. 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:264
#define DOTP(a, b)
Calculate the dot product of two vectors.
Definition: mptrac.h:699
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1535

◆ 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:567
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3404
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2868
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:3360
int np
Number of pressure levels.
Definition: mptrac.h:3357
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3369
int ntime
Number of timesteps.
Definition: mptrac.h:3351
int nlat
Number of latitudes.
Definition: mptrac.h:3354
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3363
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:2921
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:2857
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1010
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1037
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3278
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3287
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3284
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3290
int np
Number of pressure levels.
Definition: mptrac.h:3275
int no3c
Number of total ozone columns.
Definition: mptrac.h:3281
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:780
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3383
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3392
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3386
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3395
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3389
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:1138
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1880
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:1973

◆ 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:3337
double time[CTS]
Time [s].
Definition: mptrac.h:3334
int ntime
Number of timesteps.
Definition: mptrac.h:3331
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:3366
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:818
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:798
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:416
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:283

◆ 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:1696

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

1885 {
1886
1887 const int
1888 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1889 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1890
1891 int i;
1892
1893 /* Get month and day... */
1894 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
1895 for (i = 11; i > 0; i--)
1896 if (d0l[i] <= doy)
1897 break;
1898 *mon = i + 1;
1899 *day = doy - d0l[i] + 1;
1900 } else {
1901 for (i = 11; i > 0; i--)
1902 if (d0[i] <= doy)
1903 break;
1904 *mon = i + 1;
1905 *day = doy - d0[i] + 1;
1906 }
1907}

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

1914 {
1915
1916 double data[2 * EX];
1917
1918 /* Check size... */
1919 if (n > EX)
1920 ERRMSG("Too many data points!");
1921
1922 /* Allocate... */
1923 gsl_fft_complex_wavetable *wavetable =
1924 gsl_fft_complex_wavetable_alloc((size_t) n);
1925 gsl_fft_complex_workspace *workspace =
1926 gsl_fft_complex_workspace_alloc((size_t) n);
1927
1928 /* Set data (real, complex)... */
1929 for (int i = 0; i < n; i++) {
1930 data[2 * i] = fcReal[i];
1931 data[2 * i + 1] = fcImag[i];
1932 }
1933
1934 /* Calculate FFT... */
1935 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
1936
1937 /* Copy data... */
1938 for (int i = 0; i < n; i++) {
1939 fcReal[i] = data[2 * i];
1940 fcImag[i] = data[2 * i + 1];
1941 }
1942
1943 /* Free... */
1944 gsl_fft_complex_wavetable_free(wavetable);
1945 gsl_fft_complex_workspace_free(workspace);
1946}
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2043
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:288

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

1954 {
1955
1956 const double radius = z + RE;
1957 const double latrad = DEG2RAD(lat);
1958 const double lonrad = DEG2RAD(lon);
1959 const double coslat = cos(latrad);
1960
1961 x[0] = radius * coslat * cos(lonrad);
1962 x[1] = radius * coslat * sin(lonrad);
1963 x[2] = radius * sin(latrad);
1964}

◆ get_met_help()

void get_met_help ( 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 1968 of file mptrac.c.

1974 {
1975
1976 char repl[LEN];
1977
1978 double t6, r;
1979
1980 int year, mon, day, hour, min, sec;
1981
1982 /* Round time to fixed intervals... */
1983 if (direct == -1)
1984 t6 = floor(t / dt_met) * dt_met;
1985 else
1986 t6 = ceil(t / dt_met) * dt_met;
1987
1988 /* Decode time... */
1989 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1990
1991 /* Set filename of MPTRAC meteo files... */
1992 if (ctl->met_clams == 0) {
1993 if (ctl->met_type == 0)
1994 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1995 else if (ctl->met_type == 1)
1996 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1997 else if (ctl->met_type == 2)
1998 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1999 else if (ctl->met_type == 3)
2000 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
2001 else if (ctl->met_type == 4)
2002 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
2003 else if (ctl->met_type == 5)
2004 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
2005 else if (ctl->met_type == 7)
2006 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
2007 sprintf(repl, "%d", year);
2008 get_met_replace(filename, "YYYY", repl);
2009 sprintf(repl, "%02d", mon);
2010 get_met_replace(filename, "MM", repl);
2011 sprintf(repl, "%02d", day);
2012 get_met_replace(filename, "DD", repl);
2013 sprintf(repl, "%02d", hour);
2014 get_met_replace(filename, "HH", repl);
2015 }
2016
2017 /* Set filename of CLaMS meteo files... */
2018 else {
2019 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
2020 sprintf(repl, "%d", year);
2021 get_met_replace(filename, "YYYY", repl);
2022 sprintf(repl, "%02d", year % 100);
2023 get_met_replace(filename, "YY", repl);
2024 sprintf(repl, "%02d", mon);
2025 get_met_replace(filename, "MM", repl);
2026 sprintf(repl, "%02d", day);
2027 get_met_replace(filename, "DD", repl);
2028 sprintf(repl, "%02d", hour);
2029 get_met_replace(filename, "HH", repl);
2030 }
2031}
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:2035
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:2570
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:298
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2492
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:2489
Here is the call graph for this function:

◆ get_met_replace()

void get_met_replace ( char *  orig,
char *  search,
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 2035 of file mptrac.c.

2038 {
2039
2040 char buffer[LEN];
2041
2042 /* Iterate... */
2043 for (int i = 0; i < 3; i++) {
2044
2045 /* Replace sub-string... */
2046 char *ch;
2047 if (!(ch = strstr(orig, search)))
2048 return;
2049 strncpy(buffer, orig, (size_t) (ch - orig));
2050 buffer[ch - orig] = 0;
2051 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
2052 orig[0] = 0;
2053 strcpy(orig, buffer);
2054 }
2055}

◆ get_tropo()

void get_tropo ( const int  met_tropo,
ctl_t ctl,
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 2059 of file mptrac.c.

2074 {
2075
2077
2078 ctl->met_tropo = met_tropo;
2079 read_met_tropo(ctl, clim, met);
2080#pragma omp parallel for default(shared) private(ci,cw)
2081 for (int ix = 0; ix < nx; ix++)
2082 for (int iy = 0; iy < ny; iy++) {
2083 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2084 &pt[iy * nx + ix], ci, cw, 1);
2085 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2086 &ps[iy * nx + ix], ci, cw, 0);
2087 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2088 &zs[iy * nx + ix], ci, cw, 0);
2089 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2090 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2091 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2092 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2093 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2094 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2095 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2096 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2097 }
2098}
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:2359
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:10729
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:2301
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:833
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2628
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3568
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3478
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3484
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3571
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3553
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3511
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3550
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 2102 of file mptrac.c.

2110 {
2111
2112 /* Check longitude... */
2113 *lon2 = FMOD(lon, 360.);
2114 if (*lon2 < lons[0])
2115 *lon2 += 360;
2116 else if (*lon2 > lons[nlon - 1])
2117 *lon2 -= 360;
2118
2119 /* Check latitude... */
2120 *lat2 = lat;
2121 if (lats[0] < lats[nlat - 1])
2122 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
2123 else
2124 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
2125}

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

2143 {
2144
2145 if (init) {
2146
2147 /* Check longitude and latitude... */
2148 double lon2, lat2;
2149 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
2150 &lon2, &lat2);
2151
2152 /* Get horizontal indizes... */
2153 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
2154 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
2155
2156 /* Locate the vertical indizes for each edge of the column... */
2157 int ind[2][4];
2158 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
2159 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
2160
2161 /* Find minimum and maximum indizes... */
2162 ci[2] = ind[0][0];
2163 int k_max = ind[0][0];
2164 for (int i = 0; i < 2; i++)
2165 for (int j = 0; j < 4; j++) {
2166 if (ci[2] > ind[i][j])
2167 ci[2] = ind[i][j];
2168 if (k_max < ind[i][j])
2169 k_max = ind[i][j];
2170 }
2171
2172 /* Get weighting factors for time, longitude and latitude... */
2173 cw[3] = (ts - met0->time) / (met1->time - met0->time);
2174 cw[0] = (lon2 - met0->lon[ci[0]]) /
2175 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
2176 cw[1] = (lat2 - met0->lat[ci[1]]) /
2177 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
2178
2179 /* Interpolate in time at the lowest level... */
2180 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
2181 - heights0[ci[0]][ci[1]][ci[2]])
2182 + heights0[ci[0]][ci[1]][ci[2]];
2183 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
2184 - heights0[ci[0]][ci[1] + 1][ci[2]])
2185 + heights0[ci[0]][ci[1] + 1][ci[2]];
2186 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
2187 - heights0[ci[0] + 1][ci[1]][ci[2]])
2188 + heights0[ci[0] + 1][ci[1]][ci[2]];
2189 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
2190 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
2191 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
2192
2193 /* Interpolate in latitude direction... */
2194 double height0 = cw[1] * (height01 - height00) + height00;
2195 double height1 = cw[1] * (height11 - height10) + height10;
2196
2197 /* Interpolate in longitude direction... */
2198 double height_bot = cw[0] * (height1 - height0) + height0;
2199
2200 /* Interpolate in time at the upper level... */
2201 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2202 - heights0[ci[0]][ci[1]][ci[2] + 1])
2203 + heights0[ci[0]][ci[1]][ci[2] + 1];
2204 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2205 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2206 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2207 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2208 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2209 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2210 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2211 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2212 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2213
2214 /* Interpolate in latitude direction... */
2215 height0 = cw[1] * (height01 - height00) + height00;
2216 height1 = cw[1] * (height11 - height10) + height10;
2217
2218 /* Interpolate in longitude direction... */
2219 double height_top = cw[0] * (height1 - height0) + height0;
2220
2221 /* Search at higher levels if height is not in box... */
2222 while (((heights0[0][0][0] > heights0[0][0][1]) &&
2223 ((height_bot <= height) || (height_top > height))
2224 && (height_bot >= height) && (ci[2] < k_max))
2225 ||
2226 ((heights0[0][0][0] < heights0[0][0][1]) &&
2227 ((height_bot >= height) || (height_top < height))
2228 && (height_bot <= height) && (ci[2] < k_max))
2229 ) {
2230
2231 ci[2]++;
2232 height_bot = height_top;
2233
2234 /* Interpolate in time at the next level... */
2235 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2236 - heights0[ci[0]][ci[1]][ci[2] + 1])
2237 + heights0[ci[0]][ci[1]][ci[2] + 1];
2238 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2239 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2240 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2241 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2242 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2243 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2244 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2245 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2246 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2247
2248 /* Interpolate in latitude direction... */
2249 height0 = cw[1] * (height01 - height00) + height00;
2250 height1 = cw[1] * (height11 - height10) + height10;
2251
2252 /* Interpolate in longitude direction... */
2253 height_top = cw[0] * (height1 - height0) + height0;
2254 }
2255
2256 /* Get vertical weighting factors... */
2257 cw[2] = (height - height_bot)
2258 / (height_top - height_bot);
2259 }
2260
2261 /* Calculate the needed array values... */
2262 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
2263 - array0[ci[0]][ci[1]][ci[2]])
2264 + array0[ci[0]][ci[1]][ci[2]];
2265 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
2266 - array0[ci[0] + 1][ci[1]][ci[2]])
2267 + array0[ci[0] + 1][ci[1]][ci[2]];
2268 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
2269 - array0[ci[0]][ci[1] + 1][ci[2]])
2270 + array0[ci[0]][ci[1] + 1][ci[2]];
2271 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
2272 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
2273 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
2274 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
2275 - array0[ci[0]][ci[1]][ci[2] + 1])
2276 + array0[ci[0]][ci[1]][ci[2] + 1];
2277 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2278 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2279 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2280 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2281 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2282 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2283 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2284 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2285 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2286
2287 const double array00 = cw[0] * (array100 - array000) + array000;
2288 const double array10 = cw[0] * (array110 - array010) + array010;
2289 const double array01 = cw[0] * (array101 - array001) + array001;
2290 const double array11 = cw[0] * (array111 - array011) + array011;
2291
2292 const double aux0 = cw[1] * (array10 - array00) + array00;
2293 const double aux1 = cw[1] * (array11 - array01) + array01;
2294
2295 /* Interpolate vertically... */
2296 *var = cw[2] * (aux1 - aux0) + aux0;
2297}
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:2940
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:2102
int nx
Number of longitudes.
Definition: mptrac.h:3445
int ny
Number of latitudes.
Definition: mptrac.h:3448
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3457
int npl
Number of model levels.
Definition: mptrac.h:3454
double time
Time [s].
Definition: mptrac.h:3442
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3460
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 2301 of file mptrac.c.

2310 {
2311
2312 /* Initialize interpolation... */
2313 if (init) {
2314
2315 /* Check longitude and latitude... */
2316 double lon2, lat2;
2317 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2318 &lon2, &lat2);
2319
2320 /* Get interpolation indices... */
2321 ci[0] = locate_irr(met->p, met->np, p);
2322 ci[1] = locate_reg(met->lon, met->nx, lon2);
2323 ci[2] = locate_irr(met->lat, met->ny, lat2);
2324
2325 /* Get interpolation weights... */
2326 cw[0] = (met->p[ci[0] + 1] - p)
2327 / (met->p[ci[0] + 1] - met->p[ci[0]]);
2328 cw[1] = (met->lon[ci[1] + 1] - lon2)
2329 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2330 cw[2] = (met->lat[ci[2] + 1] - lat2)
2331 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2332 }
2333
2334 /* Interpolate vertically... */
2335 const double aux00 =
2336 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
2337 + array[ci[1]][ci[2]][ci[0] + 1];
2338 const double aux01 =
2339 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
2340 array[ci[1]][ci[2] + 1][ci[0] + 1])
2341 + array[ci[1]][ci[2] + 1][ci[0] + 1];
2342 const double aux10 =
2343 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
2344 array[ci[1] + 1][ci[2]][ci[0] + 1])
2345 + array[ci[1] + 1][ci[2]][ci[0] + 1];
2346 const double aux11 =
2347 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
2348 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
2349 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
2350
2351 /* Interpolate horizontally... */
2352 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2353 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2354 *var = cw[1] * (aux0 - aux1) + aux1;
2355}
int np
Number of pressure levels.
Definition: mptrac.h:3451
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3463
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 2359 of file mptrac.c.

2367 {
2368
2369 /* Initialize interpolation... */
2370 if (init) {
2371
2372 /* Check longitude and latitude... */
2373 double lon2, lat2;
2374 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2375 &lon2, &lat2);
2376
2377 /* Get interpolation indices... */
2378 ci[1] = locate_reg(met->lon, met->nx, lon2);
2379 ci[2] = locate_irr(met->lat, met->ny, lat2);
2380
2381 /* Get interpolation weights... */
2382 cw[1] = (met->lon[ci[1] + 1] - lon2)
2383 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2384 cw[2] = (met->lat[ci[2] + 1] - lat2)
2385 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2386 }
2387
2388 /* Set variables... */
2389 const double aux00 = array[ci[1]][ci[2]];
2390 const double aux01 = array[ci[1]][ci[2] + 1];
2391 const double aux10 = array[ci[1] + 1][ci[2]];
2392 const double aux11 = array[ci[1] + 1][ci[2] + 1];
2393
2394 /* Interpolate horizontally... */
2395 if (isfinite(aux00) && isfinite(aux01)
2396 && isfinite(aux10) && isfinite(aux11)) {
2397 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2398 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2399 *var = cw[1] * (aux0 - aux1) + aux1;
2400 } else {
2401 if (cw[2] < 0.5) {
2402 if (cw[1] < 0.5)
2403 *var = aux11;
2404 else
2405 *var = aux01;
2406 } else {
2407 if (cw[1] < 0.5)
2408 *var = aux10;
2409 else
2410 *var = aux00;
2411 }
2412 }
2413}
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 2417 of file mptrac.c.

2429 {
2430
2431 double var0, var1;
2432
2433 /* Spatial interpolation... */
2434 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
2435 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
2436
2437 /* Get weighting factor... */
2438 const double wt = (met1->time - ts) / (met1->time - met0->time);
2439
2440 /* Interpolate... */
2441 *var = wt * (var0 - var1) + var1;
2442}
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 2446 of file mptrac.c.

2457 {
2458
2459 double var0, var1;
2460
2461 /* Spatial interpolation... */
2462 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
2463 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
2464
2465 /* Get weighting factor... */
2466 const double wt = (met1->time - ts) / (met1->time - met0->time);
2467
2468 /* Interpolate... */
2469 if (isfinite(var0) && isfinite(var1))
2470 *var = wt * (var0 - var1) + var1;
2471 else if (wt < 0.5)
2472 *var = var1;
2473 else
2474 *var = var0;
2475}
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 2479 of file mptrac.c.

2493 {
2494
2495 double mean = 0;
2496
2497 int n = 0;
2498
2499 /* Check longitude and latitude... */
2500 double lon2, lat2;
2501 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
2502
2503 /* Get indices... */
2504 const int ix = locate_reg(lons, (int) nlon, lon2);
2505 const int iy = locate_irr(lats, (int) nlat, lat2);
2506
2507 /* Calculate standard deviation... */
2508 *sigma = 0;
2509 for (int dx = 0; dx < 2; dx++)
2510 for (int dy = 0; dy < 2; dy++) {
2511 if (isfinite(array0[ix + dx][iy + dy])) {
2512 mean += array0[ix + dx][iy + dy];
2513 *sigma += SQR(array0[ix + dx][iy + dy]);
2514 n++;
2515 }
2516 if (isfinite(array1[ix + dx][iy + dy])) {
2517 mean += array1[ix + dx][iy + dy];
2518 *sigma += SQR(array1[ix + dx][iy + dy]);
2519 n++;
2520 }
2521 }
2522 if (n > 0)
2523 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
2524
2525 /* Linear interpolation... */
2526 if (method == 1 && isfinite(array0[ix][iy])
2527 && isfinite(array0[ix][iy + 1])
2528 && isfinite(array0[ix + 1][iy])
2529 && isfinite(array0[ix + 1][iy + 1])
2530 && isfinite(array1[ix][iy])
2531 && isfinite(array1[ix][iy + 1])
2532 && isfinite(array1[ix + 1][iy])
2533 && isfinite(array1[ix + 1][iy + 1])) {
2534
2535 const double aux00 = LIN(lons[ix], array0[ix][iy],
2536 lons[ix + 1], array0[ix + 1][iy], lon2);
2537 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
2538 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2539 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2540
2541 const double aux10 = LIN(lons[ix], array1[ix][iy],
2542 lons[ix + 1], array1[ix + 1][iy], lon2);
2543 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
2544 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2545 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2546
2547 *var = LIN(time0, aux0, time1, aux1, time);
2548 }
2549
2550 /* Nearest neighbor interpolation... */
2551 else {
2552 const double aux00 = NN(lons[ix], array0[ix][iy],
2553 lons[ix + 1], array0[ix + 1][iy], lon2);
2554 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
2555 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2556 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2557
2558 const double aux10 = NN(lons[ix], array1[ix][iy],
2559 lons[ix + 1], array1[ix + 1][iy], lon2);
2560 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
2561 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2562 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2563
2564 *var = NN(time0, aux0, time1, aux1, time);
2565 }
2566}
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1386
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 2570 of file mptrac.c.

2578 {
2579
2580 struct tm t0, *t1;
2581
2582 t0.tm_year = 100;
2583 t0.tm_mon = 0;
2584 t0.tm_mday = 1;
2585 t0.tm_hour = 0;
2586 t0.tm_min = 0;
2587 t0.tm_sec = 0;
2588
2589 const time_t jsec0 = (time_t) jsec + timegm(&t0);
2590 t1 = gmtime(&jsec0);
2591
2592 *year = t1->tm_year + 1900;
2593 *mon = t1->tm_mon + 1;
2594 *day = t1->tm_mday;
2595 *hour = t1->tm_hour;
2596 *min = t1->tm_min;
2597 *sec = t1->tm_sec;
2598 *remain = jsec - floor(jsec);
2599}

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

2607 {
2608
2609 /* Check number of data points... */
2610 if (nk < 2)
2611 return 1.0;
2612
2613 /* Get altitude... */
2614 const double z = Z(p);
2615
2616 /* Get weighting factor... */
2617 if (z < kz[0])
2618 return kw[0];
2619 else if (z > kz[nk - 1])
2620 return kw[nk - 1];
2621 else {
2622 const int idx = locate_irr(kz, nk, z);
2623 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
2624 }
2625}
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 2629 of file mptrac.c.

2631 {
2632
2633 /*
2634 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
2635 and water vapor volume mixing ratio [1].
2636
2637 Reference: https://en.wikipedia.org/wiki/Lapse_rate
2638 */
2639
2640 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
2641
2642 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
2643}
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:259
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1683
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:224
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:214
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:209
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:204

◆ 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 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 press_level_def in the control structure ctl. It initializes the met_np and met_p fields accordingly.

Note
Valid values for press_level_def are:
  • 0: Define 138 pressure levels.
  • 1: Define 92 pressure levels.
  • 2: Define 60 pressure levels.
  • 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. Any other value for press_level_def will result in an error message.
Author
Jan Clemens

Definition at line 2647 of file mptrac.c.

2648 {
2649
2650 if (0 == ctl->met_press_level_def) {
2651
2652 ctl->met_np = 138;
2653
2654 const double press[138] = {
2655 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
2656 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
2657 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
2658 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
2659 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2660 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
2661 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
2662 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
2663 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
2664 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
2665 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
2666 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
2667 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2668 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2669 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2670 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2671 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2672 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2673 1010.8487, 1013.2500, 1044.45
2674 };
2675
2676 for (int ip = 0; ip < ctl->met_np; ip++)
2677 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2678
2679 } else if (1 == ctl->met_press_level_def) {
2680
2681 ctl->met_np = 92;
2682
2683 const double press[92] = {
2684 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2685 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2686 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2687 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2688 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2689 113.6382,
2690 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2691 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2692 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2693 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2694 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2695 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2696 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2697 1007.4431, 1010.8487, 1013.2500, 1044.45
2698 };
2699
2700 for (int ip = 0; ip < ctl->met_np; ip++)
2701 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2702
2703 } else if (2 == ctl->met_press_level_def) {
2704
2705 ctl->met_np = 60;
2706
2707 const double press[60] = {
2708 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2709 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2710 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2711 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2712 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2713 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2714 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2715 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
2716 };
2717
2718 for (int ip = 0; ip < ctl->met_np; ip++)
2719 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2720
2721 } else if (3 == ctl->met_press_level_def) {
2722
2723 ctl->met_np = 147;
2724
2725 const double press[147] = {
2726 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
2727 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
2728 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
2729 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
2730 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2731 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
2732 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
2733 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
2734 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
2735 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
2736 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
2737 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
2738 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2739 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2740 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2741 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2742 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2743 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2744 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
2745 1031.97,
2746 1035.09, 1038.21, 1041.33, 1044.45
2747 };
2748
2749 for (int ip = 0; ip < ctl->met_np; ip++)
2750 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2751
2752 } else if (4 == ctl->met_press_level_def) {
2753
2754 ctl->met_np = 101;
2755
2756 const double press[101] = {
2757 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2758 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2759 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2760 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2761 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2762 113.6382,
2763 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2764 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2765 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2766 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2767 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2768 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2769 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2770 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
2771 1028.85, 1031.97,
2772 1035.09, 1038.21, 1041.33, 1044.45
2773 };
2774
2775 for (int ip = 0; ip < ctl->met_np; ip++)
2776 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2777
2778 } else if (5 == ctl->met_press_level_def) {
2779
2780 ctl->met_np = 62;
2781
2782 const double press[62] = {
2783 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2784 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2785 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2786 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2787 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2788 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2789 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2790 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
2791 1044.45
2792 };
2793
2794 for (int ip = 0; ip < ctl->met_np; ip++)
2795 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2796
2797 } else if (6 == ctl->met_press_level_def) {
2798
2799 ctl->met_np = 137;
2800
2801 const double press[137] = {
2802 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
2803 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
2804 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
2805 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
2806 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
2807 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2808 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
2809 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
2810 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
2811 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
2812 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
2813 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
2814 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
2815 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
2816 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
2817 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
2818 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
2819 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
2820 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
2821 1030.06, 1037.25, 1044.45
2822 };
2823
2824 for (int ip = 0; ip < ctl->met_np; ip++)
2825 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2826
2827 } else if (7 == ctl->met_press_level_def) {
2828
2829 ctl->met_np = 59;
2830
2831 const double press[59] = {
2832 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2833 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2834 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2835 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2836 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2837 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2838 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2839 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2840 1028.53, 1046.13
2841 };
2842
2843 for (int ip = 0; ip < ctl->met_np; ip++)
2844 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2845
2846 } else {
2847 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.");
2848 }
2849
2850 if (ctl->met_np > EP) {
2851 ERRMSG("Recompile with larger EP to use this pressure level definition.");
2852 }
2853}
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2594
int met_np
Number of target pressure levels.
Definition: mptrac.h:2588
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2591

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

2860 {
2861
2862 int ilo = 0;
2863 int ihi = n - 1;
2864 int i = (ihi + ilo) >> 1;
2865
2866 if (xx[i] < xx[i + 1])
2867 while (ihi > ilo + 1) {
2868 i = (ihi + ilo) >> 1;
2869 if (xx[i] > x)
2870 ihi = i;
2871 else
2872 ilo = i;
2873 } else
2874 while (ihi > ilo + 1) {
2875 i = (ihi + ilo) >> 1;
2876 if (xx[i] <= x)
2877 ihi = i;
2878 else
2879 ilo = i;
2880 }
2881
2882 return ilo;
2883}

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

2891 {
2892
2893 int ilo = 0;
2894 int ihi = n - 1;
2895 int i = (ihi + ilo) >> 1;
2896
2897 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
2898 return ig;
2899
2900 if (xx[i] < xx[i + 1])
2901 while (ihi > ilo + 1) {
2902 i = (ihi + ilo) >> 1;
2903 if (xx[i] > x)
2904 ihi = i;
2905 else
2906 ilo = i;
2907 } else
2908 while (ihi > ilo + 1) {
2909 i = (ihi + ilo) >> 1;
2910 if (xx[i] <= x)
2911 ihi = i;
2912 else
2913 ilo = i;
2914 }
2915
2916 return ilo;
2917}

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

2924 {
2925
2926 /* Calculate index... */
2927 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2928
2929 /* Check range... */
2930 if (i < 0)
2931 return 0;
2932 else if (i > n - 2)
2933 return n - 2;
2934 else
2935 return i;
2936}

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

2946 {
2947
2948 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2949 np, height_ap, 0);
2950 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2951 np, height_ap, ind[0]);
2952 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2953 np, height_ap, ind[1]);
2954 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2955 np, height_ap, ind[2]);
2956}
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:2887
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 2960 of file mptrac.c.

2965 {
2966
2967 /* Set timer... */
2968 SELECT_TIMER("MODULE_ADVECT", "PHYSICS");
2969
2970 /* Use omega vertical velocity... */
2971 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2972
2973 /* Loop over particles... */
2974 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2975
2976 /* Init... */
2978 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2979 x[3] = { 0, 0, 0 };
2980
2981 /* Loop over integration nodes... */
2982 for (int i = 0; i < ctl->advect; i++) {
2983
2984 /* Set position... */
2985 if (i == 0) {
2986 dts = 0.0;
2987 x[0] = atm->lon[ip];
2988 x[1] = atm->lat[ip];
2989 x[2] = atm->p[ip];
2990 } else {
2991 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2992 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2993 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2994 x[2] = atm->p[ip] + dts * w[i - 1];
2995 }
2996 const double tm = atm->time[ip] + dts;
2997
2998 /* Interpolate meteo data on pressure levels... */
2999 if (ctl->advect_vert_coord == 0) {
3000 intpol_met_time_3d(met0, met0->u, met1, met1->u,
3001 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3002 intpol_met_time_3d(met0, met0->v, met1, met1->v,
3003 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3004 intpol_met_time_3d(met0, met0->w, met1, met1->w,
3005 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3006 }
3007
3008 /* Interpolate meteo data on model levels... */
3009 else {
3010 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
3011 met1, met1->pl, met1->ul,
3012 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3013 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
3014 met1, met1->pl, met1->vl,
3015 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3016 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
3017 met1, met1->pl, met1->wl,
3018 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3019 }
3020
3021 /* Get mean wind... */
3022 double k = 1.0;
3023 if (ctl->advect == 2)
3024 k = (i == 0 ? 0.0 : 1.0);
3025 else if (ctl->advect == 4)
3026 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3027 um += k * u[i];
3028 vm += k * v[i];
3029 wm += k * w[i];
3030 }
3031
3032 /* Set new position... */
3033 atm->time[ip] += cache->dt[ip];
3034 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3035 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3036 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3037 atm->p[ip] += cache->dt[ip] * wm;
3038 }
3039 }
3040
3041 /* Use zeta or eta vertical velocity... */
3042 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
3043
3044 /* Select quantity index depending on coordinate... */
3045 const int qnt = (ctl->advect_vert_coord == 1
3046 ? ctl->qnt_zeta : ctl->qnt_eta);
3047
3048 /* Loop over particles... */
3049 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3050
3051 /* Convert pressure to vertical coordinate (zeta or eta)... */
3053 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
3054 met1, met1->pl, met1->zetal,
3055 atm->time[ip], atm->p[ip],
3056 atm->lon[ip], atm->lat[ip],
3057 &atm->q[qnt][ip], ci, cw, 1);
3058
3059 /* Init... */
3060 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
3061 wdotm = 0, x[3] = { 0, 0, 0 };
3062
3063 /* Loop over integration nodes (Runge–Kutta steps)... */
3064 for (int i = 0; i < ctl->advect; i++) {
3065
3066 /* Set position... */
3067 if (i == 0) {
3068 dts = 0.0;
3069 x[0] = atm->lon[ip];
3070 x[1] = atm->lat[ip];
3071 x[2] = atm->q[qnt][ip];
3072 } else {
3073 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3074 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
3075 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
3076 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
3077 }
3078
3079 const double tm = atm->time[ip] + dts;
3080
3081 /* Interpolate meteo data... */
3082 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
3083 met1, met1->zetal, met1->ul,
3084 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3085 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
3086 met1, met1->zetal, met1->vl,
3087 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3088 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
3089 met1, met1->zetal, met1->zeta_dotl,
3090 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
3091
3092 /* Compute Runge–Kutta weights... */
3093 double k = 1.0;
3094 if (ctl->advect == 2)
3095 k = (i == 0 ? 0.0 : 1.0);
3096 else if (ctl->advect == 4)
3097 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3098
3099 um += k * u[i];
3100 vm += k * v[i];
3101 wdotm += k * wdot[i];
3102 }
3103
3104 /* Update particle position... */
3105 atm->time[ip] += cache->dt[ip];
3106 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3107 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3108 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3109 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
3110
3111 /* Convert vertical coordinate (zeta or eta) back to pressure... */
3112 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
3113 met1, met1->zetal, met1->pl,
3114 atm->time[ip],
3115 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
3116 &atm->p[ip], ci, cw, 1);
3117 }
3118 }
3119}
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:2417
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:2129
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1413
#define SELECT_TIMER(id, group)
Select and start a timer with specific attributes.
Definition: mptrac.h:2117
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:614
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:632
double time[NP]
Time [s].
Definition: mptrac.h:3191
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3200
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3197
int np
Number of air parcels.
Definition: mptrac.h:3188
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3203
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3194
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3261
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2354
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2663
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2345
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:2667
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3604
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3562
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3598
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3595
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3556
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3592
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3559
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3589
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3601
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 3123 of file mptrac.c.

3128 {
3129
3130 /* Check parameters... */
3131 if (ctl->advect_vert_coord != 1)
3132 return;
3133
3134 /* Set timer... */
3135 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS");
3136
3137 /* Loop over particles... */
3138 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
3139
3140 /* Initialize pressure consistent with zeta... */
3142 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
3143 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
3144 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
3145 }
3146}
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 3150 of file mptrac.c.

3156 {
3157
3158 /* Set timer... */
3159 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS");
3160
3161 /* Check quantity flags... */
3162 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
3163 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
3164 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
3165 return;
3166
3167 /* Loop over particles... */
3168 PARTICLE_LOOP(0, atm->np, 1,
3169 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3170
3171 /* Check latitude and pressure range... */
3172 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
3173 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
3174 continue;
3175
3176 /* Check surface layer... */
3177 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
3178 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
3179
3180 /* Get surface pressure... */
3181 double ps;
3183 INTPOL_2D(ps, 1);
3184
3185 /* Check pressure... */
3186 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
3187 continue;
3188
3189 /* Check height... */
3190 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
3191 continue;
3192
3193 /* Check zeta range... */
3194 if (ctl->bound_zetas > 0) {
3195 double t;
3196 INTPOL_3D(t, 1);
3197 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
3198 continue;
3199 }
3200
3201 /* Check planetary boundary layer... */
3202 if (ctl->bound_pbl) {
3203 double pbl;
3204 INTPOL_2D(pbl, 0);
3205 if (atm->p[ip] < pbl)
3206 continue;
3207 }
3208 }
3209
3210 /* Set mass and volume mixing ratio... */
3211 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
3212 atm->q[ctl->qnt_m][ip] =
3213 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
3214 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
3215 atm->q[ctl->qnt_vmr][ip] =
3216 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
3217
3218 /* Set CFC-10 volume mixing ratio... */
3219 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
3220 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
3221
3222 /* Set CFC-11 volume mixing ratio... */
3223 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
3224 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
3225
3226 /* Set CFC-12 volume mixing ratio... */
3227 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
3228 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
3229
3230 /* Set N2O volume mixing ratio... */
3231 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
3232 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
3233
3234 /* Set SF6 volume mixing ratio... */
3235 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
3236 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
3237
3238 /* Set age of air... */
3239 if (ctl->qnt_aoa >= 0)
3240 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
3241 }
3242}
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:864
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1930
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:847
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3422
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3428
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3416
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3419
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3425
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2423
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2162
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2432
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2793
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2742
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2417
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2715
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2165
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2730
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2748
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2736
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2721
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2727
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2724
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2426
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2420
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2429
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2739
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2718
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2733
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2784
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2796
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2787
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2790
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2745
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 3246 of file mptrac.c.

3251 {
3252
3253 /* Check quantities... */
3254 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
3255 return;
3256 if (ctl->molmass <= 0)
3257 ERRMSG("Molar mass is not defined!");
3258
3259 /* Set timer... */
3260 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS");
3261
3262 /* Allocate... */
3263 const int ensemble_mode = (ctl->nens > 0);
3264 const int np = atm->np;
3265 const int nz = ctl->chemgrid_nz;
3266 const int nx = ctl->chemgrid_nx;
3267 const int ny = ctl->chemgrid_ny;
3268 const int ngrid = nx * ny * nz;
3269 const int nens = ensemble_mode ? ctl->nens : 1;
3270
3271 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
3272 double *restrict const press =
3273 (double *) malloc((size_t) nz * sizeof(double));
3274 double *restrict const mass =
3275 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
3276 double *restrict const area =
3277 (double *) malloc((size_t) ny * sizeof(double));
3278 double *restrict const lon =
3279 (double *) malloc((size_t) nx * sizeof(double));
3280 double *restrict const lat =
3281 (double *) malloc((size_t) ny * sizeof(double));
3282
3283 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3284 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3285 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3286
3287 /* Set grid box size... */
3288 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
3289 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
3290 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
3291
3292 /* Set vertical coordinates... */
3293#ifdef _OPENACC
3294#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])
3295#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
3296#pragma acc parallel loop independent gang vector
3297#else
3298#pragma omp parallel for default(shared)
3299#endif
3300 for (int iz = 0; iz < nz; iz++) {
3301 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
3302 press[iz] = P(z[iz]);
3303 }
3304
3305 /* Set time interval for output... */
3306 const double t0 = tt - 0.5 * ctl->dt_mod;
3307 const double t1 = tt + 0.5 * ctl->dt_mod;
3308
3309 /* Get indices... */
3310#ifdef _OPENACC
3311#pragma acc parallel loop independent gang vector
3312#else
3313#pragma omp parallel for default(shared)
3314#endif
3315 for (int ip = 0; ip < np; ip++) {
3316 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
3317 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
3318 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
3319 if (atm->time[ip] < t0 || atm->time[ip] > t1
3320 || ixs[ip] < 0 || ixs[ip] >= nx
3321 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
3322 izs[ip] = -1;
3323 }
3324
3325 /* Set horizontal coordinates... */
3326#ifdef _OPENACC
3327#pragma acc parallel loop independent gang vector
3328#else
3329#pragma omp parallel for default(shared)
3330#endif
3331 for (int ix = 0; ix < nx; ix++)
3332 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3333
3334#ifdef _OPENACC
3335#pragma acc parallel loop independent gang vector
3336#else
3337#pragma omp parallel for default(shared)
3338#endif
3339 for (int iy = 0; iy < ny; iy++) {
3340 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3341 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3342 }
3343
3344 /* Get mass per grid box... */
3345#ifdef _OPENACC
3346#pragma acc parallel loop independent gang vector
3347#endif
3348 for (int ip = 0; ip < np; ip++) {
3349 if (izs[ip] >= 0) {
3350 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3351 if (ensemble_mode) {
3352 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3353 mass_idx += ens * ngrid;
3354 }
3355#ifdef _OPENACC
3356#pragma acc atomic update
3357#endif
3358 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
3359 }
3360 }
3361
3362 /* Assign grid data to air parcels ... */
3363#ifdef _OPENACC
3364#pragma acc parallel loop independent gang vector
3365#else
3366#pragma omp parallel for default(shared)
3367#endif
3368 for (int ip = 0; ip < np; ip++)
3369 if (izs[ip] >= 0) {
3370
3371 /* Interpolate temperature... */
3372 double temp;
3374 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
3375 press[izs[ip]],
3376 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
3377
3378 /* Set mass... */
3379 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3380 if (ensemble_mode) {
3381 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3382 mass_idx += ens * ngrid;
3383 }
3384
3385 /* Calculate volume mixing ratio... */
3386 const double m = mass[mass_idx];
3387 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
3388 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
3389 }
3390
3391 /* Free... */
3392#ifdef _OPENACC
3393#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
3394#endif
3395 free(mass);
3396 free(lon);
3397 free(lat);
3398 free(area);
3399 free(z);
3400 free(press);
3401 free(ixs);
3402 free(iys);
3403 free(izs);
3404}
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:458
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:239
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1443
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1620
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2754
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2841
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2838
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2856
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2859
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2847
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2850
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2468
int nens
Number of ensembles.
Definition: mptrac.h:3010
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2835
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2844
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2853
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2156
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2387
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 3408 of file mptrac.c.

3414 {
3415
3416 /* Set timer... */
3417 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS");
3418
3419 /* Loop over particles... */
3420 PARTICLE_LOOP(0, atm->np, 0,
3421 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3422
3423 /* Set H2O and O3 using meteo data... */
3425 if (ctl->qnt_Ch2o >= 0) {
3426 double h2o;
3427 INTPOL_3D(h2o, 1);
3428 SET_ATM(qnt_Ch2o, h2o);
3429 }
3430 if (ctl->qnt_Co3 >= 0) {
3431 double o3;
3432 INTPOL_3D(o3, 1);
3433 SET_ATM(qnt_Co3, o3);
3434 }
3435
3436 /* Set radical species... */
3437 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
3438 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3439 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
3440 atm->lat[ip], atm->p[ip]));
3441 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
3442 atm->lat[ip], atm->p[ip]));
3443 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
3444 atm->lat[ip], atm->p[ip]));
3445 }
3446}
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:1639
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3410
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3413
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3407
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2390
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2393
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 3450 of file mptrac.c.

3455 {
3456
3457 /* Set timer... */
3458 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS");
3459
3460 /* Create random numbers... */
3461 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
3462
3463 /* Loop over particles... */
3464 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3465
3466 /* Interpolate surface pressure... */
3467 double ps;
3469 INTPOL_2D(ps, 1);
3470
3471 /* Initialize pressure range for vertical mixing... */
3472 double pbot = ps, ptop = ps;
3473
3474 /* Mixing in the PBL... */
3475 if (ctl->conv_mix_pbl) {
3476
3477 /* Interpolate PBL... */
3478 double pbl;
3479 INTPOL_2D(pbl, 0);
3480
3481 /* Set pressure range... */
3482 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
3483 }
3484
3485 /* Convective mixing... */
3486 if (ctl->conv_cape >= 0) {
3487
3488 /* Interpolate CAPE, CIN, and equilibrium level... */
3489 double cape, cin, pel;
3490 INTPOL_2D(cape, 0);
3491 INTPOL_2D(cin, 0);
3492 INTPOL_2D(pel, 0);
3493
3494 /* Set pressure range... */
3495 if (isfinite(cape) && cape >= ctl->conv_cape
3496 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
3497 ptop = GSL_MIN(ptop, pel);
3498 }
3499
3500 /* Apply vertical mixing... */
3501 if (ptop != pbot && atm->p[ip] >= ptop) {
3502
3503 /* Get density range... */
3504 double tbot, ttop;
3505 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
3506 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
3507 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
3508 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
3509 const double rhobot = pbot / tbot;
3510 const double rhotop = ptop / ttop;
3511
3512 /* Get new density... */
3513 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
3514
3515 /* Get pressure... */
3516 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
3517 }
3518 }
3519}
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:4682
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3258
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2706
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2703
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2700
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2709
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 3563 of file mptrac.c.

3567 {
3568
3569 /* Set timer... */
3570 SELECT_TIMER("MODULE_DECAY", "PHYSICS");
3571
3572 /* Check quantity flags... */
3573 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3574 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3575
3576 /* Loop over particles... */
3577 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
3578
3579 /* Get weighting factor... */
3580 const double w = tropo_weight(clim, atm, ip);
3581
3582 /* Set lifetime... */
3583 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
3584
3585 /* Calculate exponential decay... */
3586 const double aux = exp(-cache->dt[ip] / tdec);
3587 if (ctl->qnt_m >= 0) {
3588 if (ctl->qnt_mloss_decay >= 0)
3589 atm->q[ctl->qnt_mloss_decay][ip]
3590 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3591 atm->q[ctl->qnt_m][ip] *= aux;
3592 if (ctl->qnt_loss_rate >= 0)
3593 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
3594 }
3595 if (ctl->qnt_vmr >= 0)
3596 atm->q[ctl->qnt_vmr][ip] *= aux;
3597 }
3598}
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:11309
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2321
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2318
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2760
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2757
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 3602 of file mptrac.c.

3607 {
3608
3609 /* Set timer... */
3610 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS");
3611
3612 /* Create random numbers... */
3613 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3614
3615 /* Loop over particles... */
3616 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3617
3618 /* Get indices... */
3619 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
3620 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
3621 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
3622
3623 /* Get standard deviations of local wind data... */
3624 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
3625 for (int i = 0; i < 2; i++)
3626 for (int j = 0; j < 2; j++)
3627 for (int k = 0; k < 2; k++) {
3628 umean += met0->u[ix + i][iy + j][iz + k];
3629 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
3630 vmean += met0->v[ix + i][iy + j][iz + k];
3631 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
3632 wmean += met0->w[ix + i][iy + j][iz + k];
3633 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
3634
3635 umean += met1->u[ix + i][iy + j][iz + k];
3636 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
3637 vmean += met1->v[ix + i][iy + j][iz + k];
3638 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
3639 wmean += met1->w[ix + i][iy + j][iz + k];
3640 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
3641 }
3642 usig = usig / 16.f - SQR(umean / 16.f);
3643 usig = (usig > 0 ? sqrtf(usig) : 0);
3644 vsig = vsig / 16.f - SQR(vmean / 16.f);
3645 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
3646 wsig = wsig / 16.f - SQR(wmean / 16.f);
3647 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
3648
3649 /* Set temporal correlations for mesoscale fluctuations... */
3650 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
3651 const double r2 = sqrt(1 - r * r);
3652
3653 /* Calculate horizontal mesoscale wind fluctuations... */
3654 if (ctl->turb_mesox > 0) {
3655 cache->uvwp[ip][0] =
3656 (float) (r * cache->uvwp[ip][0] +
3657 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
3658 atm->lon[ip] +=
3659 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3660
3661 cache->uvwp[ip][1] =
3662 (float) (r * cache->uvwp[ip][1] +
3663 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
3664 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3665 }
3666
3667 /* Calculate vertical mesoscale wind fluctuations... */
3668 if (ctl->turb_mesoz > 0) {
3669 cache->uvwp[ip][2] =
3670 (float) (r * cache->uvwp[ip][2] +
3671 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
3672 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
3673 }
3674 }
3675}
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3255
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2697
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2478
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2694
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 3679 of file mptrac.c.

3684 {
3685
3686 /* Set timer... */
3687 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS");
3688
3689 /* Create random numbers... */
3690 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3691
3692 /* Loop over particles... */
3693 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3694
3695 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
3696 tau_u = 300., tau_w = 100.;
3697
3698 /* Get surface and PBL pressure... */
3699 double pbl, ps;
3701 INTPOL_2D(ps, 1);
3702 INTPOL_2D(pbl, 0);
3703
3704 /* Boundary layer... */
3705 if (atm->p[ip] >= pbl) {
3706
3707 /* Calculate heights... */
3708 const double p = MIN(atm->p[ip], ps);
3709 const double zs = Z(ps);
3710 const double z = 1e3 * (Z(p) - zs);
3711 const double zi = 1e3 * (Z(pbl) - zs);
3712 const double zratio = z / zi;
3713
3714 /* Calculate friction velocity... */
3715 double ess, nss, h2o, t;
3716 INTPOL_2D(ess, 0);
3717 INTPOL_2D(nss, 0);
3718 INTPOL_3D(t, 1);
3719 INTPOL_3D(h2o, 0);
3720 const double rho = RHO(p, TVIRT(t, h2o));
3721 const double tau = sqrt(SQR(ess) + SQR(nss));
3722 const double ustar = sqrt(tau / rho);
3723
3724 /* Get surface sensible heat flux... */
3725 double shf;
3726 INTPOL_2D(shf, 1);
3727
3728 /* Stable or neutral conditions... */
3729 if (shf <= 0) {
3730
3731 /* Calcalute turbulent velocity variances... */
3732 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
3733 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
3734
3735 /* Calculate derivative dsig_w/dz... */
3736 dsigw_dz = -1.3 * ustar / zi;
3737
3738 /* Calcalute Lagrangian timescales... */
3739 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
3740 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
3741 }
3742
3743 /* Unstable conditions... */
3744 else {
3745
3746 /* Convective velocity... */
3747 const double wstar =
3748 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
3749
3750 /* Calcalute turbulent velocity variances... */
3751 sig_u = 1e-2
3752 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
3753 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
3754 * pow(zratio, 2.0 / 3.0)
3755 + (1.8 - 1.4 * zratio) * SQR(ustar));
3756
3757 /* Calculate derivative dsig_w/dz... */
3758 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
3759 * (0.8 *
3760 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
3761 - 1.8 * pow(zratio, 2.0 / 3.0)));
3762
3763 /* Calculate Lagrangian timescales... */
3764 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
3765 const double eps =
3766 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
3767 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
3768 tau_u = 2 * SQR(sig_u) / (C0 * eps);
3769 tau_w = 2 * SQR(sig_w) / (C0 * eps);
3770 }
3771 }
3772
3773 /* Set minimum values... */
3774 sig_u = MAX(sig_u, 0.25);
3775 sig_w = MAX(sig_w, 0.1);
3776 tau_u = MAX(tau_u, 300.);
3777 tau_w = MAX(tau_w, 100.);
3778
3779 /* Update perturbations... */
3780 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
3781 const double ru2 = sqrt(1.0 - SQR(ru));
3782 cache->uvwp[ip][0]
3783 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
3784 cache->uvwp[ip][1]
3785 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
3786
3787 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
3788 const double rw2 = sqrt(1.0 - SQR(rw));
3789 cache->uvwp[ip][2]
3790 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
3791 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
3792
3793 /* Calculate new air parcel position... */
3794 atm->lon[ip] +=
3795 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3796 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3797 atm->p[ip] +=
3798 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
3799 }
3800}
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1858
#define KARMAN
Karman's constant.
Definition: mptrac.h:229
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1812
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:651
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 3804 of file mptrac.c.

3810 {
3811
3812 /* Set timer... */
3813 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS");
3814
3815 /* Create random numbers... */
3816 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3817
3818 /* Loop over particles... */
3819 PARTICLE_LOOP(0, atm->np, 1,
3820 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3821
3822 /* Get PBL and surface pressure... */
3823 double pbl, ps;
3825 INTPOL_2D(pbl, 1);
3826 INTPOL_2D(ps, 0);
3827
3828 /* Get weighting factors... */
3829 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
3830 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
3831 const double wstrat = 1.0 - wpbl - wtrop;
3832
3833 /* Set diffusivity... */
3834 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
3835 + wstrat * ctl->turb_dx_strat;
3836 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
3837 + wstrat * ctl->turb_dz_strat;
3838
3839 /* Horizontal turbulent diffusion... */
3840 if (dx > 0) {
3841 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
3842 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
3843 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
3844 }
3845
3846 /* Vertical turbulent diffusion... */
3847 if (dz > 0) {
3848 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
3849 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
3850 }
3851 }
3852}
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:7059
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2688
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2682
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2679
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2676
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2691
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2685
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 3856 of file mptrac.c.

3861 {
3862
3863 /* Set timer... */
3864 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS");
3865
3866 /* Check quantity flags... */
3867 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3868 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3869
3870 /* Loop over particles... */
3871 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3872
3873 /* Get surface pressure... */
3874 double ps;
3876 INTPOL_2D(ps, 1);
3877
3878 /* Check whether particle is above the surface layer... */
3879 if (atm->p[ip] < ps - ctl->dry_depo_dp)
3880 continue;
3881
3882 /* Set depth of surface layer... */
3883 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
3884
3885 /* Calculate sedimentation velocity for particles... */
3886 double v_dep;
3887 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
3888
3889 /* Get temperature... */
3890 double t;
3891 INTPOL_3D(t, 1);
3892
3893 /* Set deposition velocity... */
3894 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3895 atm->q[ctl->qnt_rhop][ip]);
3896 }
3897
3898 /* Use explicit sedimentation velocity for gases... */
3899 else
3900 v_dep = ctl->dry_depo_vdep;
3901
3902 /* Calculate loss of mass based on deposition velocity... */
3903 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3904 if (ctl->qnt_m >= 0) {
3905 if (ctl->qnt_mloss_dry >= 0)
3906 atm->q[ctl->qnt_mloss_dry][ip]
3907 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3908 atm->q[ctl->qnt_m][ip] *= aux;
3909 if (ctl->qnt_loss_rate >= 0)
3910 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3911 }
3912 if (ctl->qnt_vmr >= 0)
3913 atm->q[ctl->qnt_vmr][ip] *= aux;
3914 }
3915}
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:11074
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2171
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2168
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2916
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2315
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2919
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 3919 of file mptrac.c.

3925 {
3926
3927 /* Set timer... */
3928 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS");
3929
3930 /* Check quantity flags... */
3931 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3932 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3933
3934 /* Parameter of SO2 correction... */
3935 const double a = 3.12541941e-06;
3936 const double b = -5.72532259e-01;
3937 const double low = pow(1. / a, 1. / b);
3938
3939 /* Loop over particles... */
3940 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3941
3942 /* Check whether particle is inside cloud... */
3943 double lwc, rwc;
3945 INTPOL_3D(lwc, 1);
3946 INTPOL_3D(rwc, 0);
3947 if (!(lwc > 0 || rwc > 0))
3948 continue;
3949
3950 /* Get temperature... */
3951 double t;
3952 INTPOL_3D(t, 0);
3953
3954 /* Get molecular density... */
3955 const double M = MOLEC_DENS(atm->p[ip], t);
3956
3957 /* Reaction rate (Berglen et al., 2004)... */
3958 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3959
3960 /* Henry constant of SO2... */
3961 const double H_SO2 =
3962 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3963 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3964
3965 /* Henry constant of H2O2... */
3966 const double H_h2o2 =
3967 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3968
3969 /* Correction factor for high SO2 concentration
3970 (if qnt_Cx is defined, the correction is switched on)... */
3971 double cor = 1.0;
3972 if (ctl->qnt_Cx >= 0)
3973 cor = atm->q[ctl->qnt_Cx][ip] >
3974 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3975
3976 const double h2o2 = H_h2o2
3977 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3978 * M * cor * 1000. / AVO; /* unit: mol/L */
3979
3980 /* Volume water content in cloud [m^3 m^(-3)]... */
3981 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3982 const double CWC = (lwc + rwc) * rho_air / 1e3;
3983
3984 /* Calculate exponential decay (Rolph et al., 1992)... */
3985 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3986 const double aux = exp(-cache->dt[ip] * rate_coef);
3987 if (ctl->qnt_m >= 0) {
3988 if (ctl->qnt_mloss_h2o2 >= 0)
3989 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3990 atm->q[ctl->qnt_m][ip] *= aux;
3991 if (ctl->qnt_loss_rate >= 0)
3992 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3993 }
3994 if (ctl->qnt_vmr >= 0)
3995 atm->q[ctl->qnt_vmr][ip] *= aux;
3996 }
3997}
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:199
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1153
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:269
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2306
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 4001 of file mptrac.c.

4006 {
4007
4008 double t;
4009
4010 /* Set timer... */
4011 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS");
4012
4013 /* Save pressure... */
4014 if (ctl->isosurf == 1) {
4015 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
4016 cache->iso_var[ip] = atm->p[ip];
4017 }
4018 }
4019
4020 /* Save density... */
4021 else if (ctl->isosurf == 2) {
4022 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4024 INTPOL_3D(t, 1);
4025 cache->iso_var[ip] = atm->p[ip] / t;
4026 }
4027 }
4028
4029 /* Save potential temperature... */
4030 else if (ctl->isosurf == 3) {
4031 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4033 INTPOL_3D(t, 1);
4034 cache->iso_var[ip] = THETA(atm->p[ip], t);
4035 }
4036 }
4037
4038 /* Read balloon pressure data... */
4039 else if (ctl->isosurf == 4) {
4040
4041 /* Write info... */
4042 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
4043
4044 /* Open file... */
4045 FILE *in;
4046 if (!(in = fopen(ctl->balloon, "r")))
4047 ERRMSG("Cannot open file!");
4048
4049 /* Read pressure time series... */
4050 char line[LEN];
4051 while (fgets(line, LEN, in))
4052 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
4053 &(cache->iso_ps[cache->iso_n])) == 2)
4054 if ((++cache->iso_n) > NP)
4055 ERRMSG("Too many data points!");
4056
4057 /* Check number of points... */
4058 if (cache->iso_n < 1)
4059 ERRMSG("Could not read any data!");
4060
4061 /* Close file... */
4062 fclose(in);
4063
4064 /* Update of cache data on device... */
4065 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4066 }
4067}
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:6728
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1783
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:308
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3249
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3252
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3246
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3243
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2660
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2657
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 4071 of file mptrac.c.

4076 {
4077
4078 /* Set timer... */
4079 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS");
4080
4081 /* Loop over particles... */
4082 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4083
4084 /* Init... */
4085 double t;
4087
4088 /* Restore pressure... */
4089 if (ctl->isosurf == 1)
4090 atm->p[ip] = cache->iso_var[ip];
4091
4092 /* Restore density... */
4093 else if (ctl->isosurf == 2) {
4094 INTPOL_3D(t, 1);
4095 atm->p[ip] = cache->iso_var[ip] * t;
4096 }
4097
4098 /* Restore potential temperature... */
4099 else if (ctl->isosurf == 3) {
4100 INTPOL_3D(t, 1);
4101 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
4102 }
4103
4104 /* Interpolate pressure... */
4105 else if (ctl->isosurf == 4) {
4106 if (atm->time[ip] <= cache->iso_ts[0])
4107 atm->p[ip] = cache->iso_ps[0];
4108 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
4109 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
4110 else {
4111 const int idx =
4112 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
4113 atm->p[ip] =
4114 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
4115 cache->iso_ps[idx + 1], atm->time[ip]);
4116 }
4117 }
4118 }
4119}
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 4177 of file mptrac.c.

4183 {
4184
4185 /* Set timer... */
4186 SELECT_TIMER("MODULE_METEO", "PHYSICS");
4187
4188 /* Check quantity flags... */
4189 if (ctl->qnt_tsts >= 0)
4190 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
4191 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
4192
4193 /* Loop over particles... */
4194 PARTICLE_LOOP(0, atm->np, 0,
4195 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4196
4197 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
4198 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
4199 o3, lwc, rwc, iwc, swc, cc, z, zt;
4200
4201 /* Interpolate meteo data... */
4203 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
4204
4205 /* Set quantities... */
4206 SET_ATM(qnt_ps, ps);
4207 SET_ATM(qnt_ts, ts);
4208 SET_ATM(qnt_zs, zs);
4209 SET_ATM(qnt_us, us);
4210 SET_ATM(qnt_vs, vs);
4211 SET_ATM(qnt_ess, ess);
4212 SET_ATM(qnt_nss, nss);
4213 SET_ATM(qnt_shf, shf);
4214 SET_ATM(qnt_lsm, lsm);
4215 SET_ATM(qnt_sst, sst);
4216 SET_ATM(qnt_pbl, pbl);
4217 SET_ATM(qnt_pt, pt);
4218 SET_ATM(qnt_tt, tt);
4219 SET_ATM(qnt_zt, zt);
4220 SET_ATM(qnt_h2ot, h2ot);
4221 SET_ATM(qnt_zg, z);
4222 SET_ATM(qnt_p, atm->p[ip]);
4223 SET_ATM(qnt_t, t);
4224 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
4225 SET_ATM(qnt_u, u);
4226 SET_ATM(qnt_v, v);
4227 SET_ATM(qnt_w, w);
4228 SET_ATM(qnt_h2o, h2o);
4229 SET_ATM(qnt_o3, o3);
4230 SET_ATM(qnt_lwc, lwc);
4231 SET_ATM(qnt_rwc, rwc);
4232 SET_ATM(qnt_iwc, iwc);
4233 SET_ATM(qnt_swc, swc);
4234 SET_ATM(qnt_cc, cc);
4235 SET_ATM(qnt_pct, pct);
4236 SET_ATM(qnt_pcb, pcb);
4237 SET_ATM(qnt_cl, cl);
4238 SET_ATM(qnt_plcl, plcl);
4239 SET_ATM(qnt_plfc, plfc);
4240 SET_ATM(qnt_pel, pel);
4241 SET_ATM(qnt_cape, cape);
4242 SET_ATM(qnt_cin, cin);
4243 SET_ATM(qnt_o3c, o3c);
4244 SET_ATM(qnt_hno3,
4245 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
4246 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
4247 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4248 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
4249 atm->lat[ip], atm->p[ip]));
4250 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
4251 atm->lat[ip], atm->p[ip]));
4252 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
4253 atm->lat[ip], atm->p[ip]));
4254 SET_ATM(qnt_vh, sqrt(u * u + v * v));
4255 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
4256 SET_ATM(qnt_psat, PSAT(t));
4257 SET_ATM(qnt_psice, PSICE(t));
4258 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
4259 SET_ATM(qnt_sh, SH(h2o));
4260 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
4261 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
4262 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
4263 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
4264 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
4265 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
4266 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
4267 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
4268 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
4269 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
4270 SET_ATM(qnt_pv, pv);
4271 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
4272 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
4273 SET_ATM(qnt_tnat,
4274 nat_temperature(atm->p[ip], h2o,
4275 clim_zm(&clim->hno3, atm->time[ip],
4276 atm->lat[ip], atm->p[ip])));
4277 SET_ATM(qnt_tsts,
4278 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
4279 }
4280}
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:7035
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:2629
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1518
#define H0
Scale height [km].
Definition: mptrac.h:219
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1491
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1759
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1595
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:937
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1565
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1734
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1467
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3401
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2384
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2357
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2378
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2351
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2381
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 4284 of file mptrac.c.

4288 {
4289
4290 /* Set timer... */
4291 SELECT_TIMER("MODULE_MIXING", "PHYSICS");
4292
4293 /* Allocate... */
4294 const int np = atm->np;
4295 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
4296 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
4297 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
4298
4299 /* Set grid box size... */
4300 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
4301 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
4302 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
4303
4304 /* Set time interval... */
4305 const double t0 = t - 0.5 * ctl->dt_mod;
4306 const double t1 = t + 0.5 * ctl->dt_mod;
4307
4308 /* Get indices... */
4309#ifdef _OPENACC
4310#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
4311#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
4312#pragma acc parallel loop independent gang vector
4313#else
4314#pragma omp parallel for default(shared)
4315#endif
4316 for (int ip = 0; ip < np; ip++) {
4317 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
4318 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
4319 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
4320 if (atm->time[ip] < t0 || atm->time[ip] > t1
4321 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
4322 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
4323 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
4324 izs[ip] = -1;
4325 }
4326
4327 /* Calculate interparcel mixing... */
4328 const int use_ensemble = (ctl->nens > 0);
4329
4330 const int quantities[] = {
4331 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
4332 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
4333 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
4334 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
4335 ctl->qnt_Csf6, ctl->qnt_aoa, ctl->qnt_Arn222, ctl->qnt_Apb210,
4336 ctl->qnt_Abe7, ctl->qnt_Acs137, ctl->qnt_Ai131, ctl->qnt_Axe133
4337 };
4338 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
4339
4340 for (int i = 0; i < n_qnt; i++)
4341 if (quantities[i] >= 0)
4342 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
4343 use_ensemble);
4344
4345 /* Free... */
4346#ifdef _OPENACC
4347#pragma acc exit data delete(ixs,iys,izs)
4348#endif
4349 free(ixs);
4350 free(iys);
4351 free(izs);
4352}
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:4356
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2399
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2817
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2814
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2411
int qnt_Acs137
Quantity array index for radioactive activity of Cs-137.
Definition: mptrac.h:2444
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2811
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2396
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2826
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2402
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2829
int qnt_Ai131
Quantity array index for radioactive activity of I-131.
Definition: mptrac.h:2447
int qnt_Apb210
Quantity array index for radioactive activity of Pb-210.
Definition: mptrac.h:2438
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2405
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2808
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2820
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2832
int qnt_Axe133
Quantity array index for radioactive activity of Xe-133.
Definition: mptrac.h:2450
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2414
int qnt_Abe7
Quantity array index for radioactive activity of Be-7.
Definition: mptrac.h:2441
int qnt_Arn222
Quantity array index for radioactive activity of Rn-222.
Definition: mptrac.h:2435
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2408
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2823
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 4356 of file mptrac.c.

4364 {
4365
4366 const int np = atm->np;
4367 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
4368 const int nens = use_ensemble ? ctl->nens : 1;
4369 const int total_grid = ngrid * nens;
4370
4371 double *restrict const cmean =
4372 (double *) malloc((size_t) total_grid * sizeof(double));
4373 int *restrict const count =
4374 (int *) malloc((size_t) total_grid * sizeof(int));
4375
4376 /* Init... */
4377#ifdef _OPENACC
4378#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
4379#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
4380#pragma acc parallel loop independent gang vector
4381#else
4382#ifdef __NVCOMPILER
4383#pragma novector
4384#endif
4385#pragma omp parallel for
4386#endif
4387 for (int i = 0; i < total_grid; i++) {
4388 count[i] = 0;
4389 cmean[i] = 0.0;
4390 }
4391
4392 /* Loop over particles... */
4393#ifdef _OPENACC
4394#pragma acc parallel loop independent gang vector
4395#endif
4396 for (int ip = 0; ip < np; ip++)
4397 if (izs[ip] >= 0) {
4398 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4399 const int idx =
4400 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4401 ctl->mixing_nz);
4402#ifdef _OPENACC
4403#pragma acc atomic update
4404#endif
4405 cmean[idx] += atm->q[qnt_idx][ip];
4406#ifdef _OPENACC
4407#pragma acc atomic update
4408#endif
4409 count[idx]++;
4410 }
4411
4412 /* Compute means... */
4413#ifdef _OPENACC
4414#pragma acc parallel loop independent gang vector
4415#else
4416#ifdef __NVCOMPILER
4417#pragma novector
4418#endif
4419#pragma omp parallel for
4420#endif
4421 for (int i = 0; i < total_grid; i++)
4422 if (count[i] > 0)
4423 cmean[i] /= count[i];
4424
4425 /* Interparcel mixing... */
4426#ifdef _OPENACC
4427#pragma acc parallel loop independent gang vector
4428#else
4429#pragma omp parallel for
4430#endif
4431 for (int ip = 0; ip < np; ip++) {
4432 if (izs[ip] >= 0) {
4433 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4434
4435 double mixparam = 1.0;
4436 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
4437 const double w = tropo_weight(clim, atm, ip);
4438 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
4439 }
4440
4441 const int idx =
4442 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4443 ctl->mixing_nz);
4444 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
4445 }
4446 }
4447
4448 /* Free... */
4449#ifdef _OPENACC
4450#pragma acc exit data delete(cmean,count)
4451#endif
4452 free(cmean);
4453 free(count);
4454}
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2802
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2805
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 4458 of file mptrac.c.

4464 {
4465
4466 /* Set timer... */
4467 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS");
4468
4469 /* Check quantity flags... */
4470 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4471 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4472
4473 /* Parameter of SO2 correction... */
4474 const double a = 4.71572206e-08;
4475 const double b = -8.28782867e-01;
4476 const double low = pow(1. / a, 1. / b);
4477
4478 /* Loop over particles... */
4479 PARTICLE_LOOP(0, atm->np, 1,
4480 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4481
4482 /* Get temperature... */
4483 double t;
4485 INTPOL_3D(t, 1);
4486
4487 /* Calculate molecular density... */
4488 const double M = MOLEC_DENS(atm->p[ip], t);
4489
4490 /* Use constant reaction rate... */
4491 double k = NAN;
4492 if (ctl->oh_chem_reaction == 1)
4493 k = ctl->oh_chem[0];
4494
4495 /* Calculate bimolecular reaction rate... */
4496 else if (ctl->oh_chem_reaction == 2)
4497 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
4498
4499 /* Calculate termolecular reaction rate... */
4500 if (ctl->oh_chem_reaction == 3) {
4501
4502 /* Calculate rate coefficient for X + OH + M -> XOH + M
4503 (JPL Publication 19-05) ... */
4504 const double k0 =
4505 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
4506 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
4507 const double ki =
4508 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
4509 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
4510 const double c = log10(k0 * M / ki);
4511 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
4512 }
4513
4514 /* Correction factor for high SO2 concentration
4515 (if qnt_Cx is defined, the correction is switched on)... */
4516 double cor = 1;
4517 if (ctl->qnt_Cx >= 0)
4518 cor =
4519 atm->q[ctl->qnt_Cx][ip] >
4520 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
4521
4522 /* Calculate exponential decay... */
4523 const double rate_coef =
4524 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
4525 atm->lat[ip], atm->p[ip]) * M * cor;
4526 const double aux = exp(-cache->dt[ip] * rate_coef);
4527 if (ctl->qnt_m >= 0) {
4528 if (ctl->qnt_mloss_oh >= 0)
4529 atm->q[ctl->qnt_mloss_oh][ip]
4530 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4531 atm->q[ctl->qnt_m][ip] *= aux;
4532 if (ctl->qnt_loss_rate >= 0)
4533 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4534 }
4535 if (ctl->qnt_vmr >= 0)
4536 atm->q[ctl->qnt_vmr][ip] *= aux;
4537 }
4538}
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2865
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2862
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2303
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 4542 of file mptrac.c.

4546 {
4547
4548 /* Set timer... */
4549 SELECT_TIMER("MODULE_POSITION", "PHYSICS");
4550
4551 /* Loop over particles... */
4552 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
4553
4554 /* Init... */
4555 double ps;
4557
4558 /* Calculate modulo... */
4559 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
4560 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
4561
4562 /* Check latitude... */
4563 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
4564 if (atm->lat[ip] > 90) {
4565 atm->lat[ip] = 180 - atm->lat[ip];
4566 atm->lon[ip] += 180;
4567 }
4568 if (atm->lat[ip] < -90) {
4569 atm->lat[ip] = -180 - atm->lat[ip];
4570 atm->lon[ip] += 180;
4571 }
4572 }
4573
4574 /* Check longitude... */
4575 while (atm->lon[ip] < -180)
4576 atm->lon[ip] += 360;
4577 while (atm->lon[ip] >= 180)
4578 atm->lon[ip] -= 360;
4579
4580 /* Check pressure... */
4581 if (atm->p[ip] < met0->p[met0->np - 1]) {
4582 atm->p[ip] = met0->p[met0->np - 1];
4583 } else if (atm->p[ip] > 300.) {
4584 INTPOL_2D(ps, 1);
4585 if (atm->p[ip] > ps)
4586 atm->p[ip] = ps;
4587 }
4588 }
4589}

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

4596 {
4597
4598 /* Set timer... */
4599 SELECT_TIMER("MODULE_RADIO_DECAY", "PHYSICS");
4600
4601 /* Set decay constants of radioactive species [s^-1]... */
4602 const double lambda_rn222 = log(2.0) / (3.8235 * 86400.0);
4603 const double lambda_pb210 = log(2.0) / (22.3 * 365.25 * 86400.0);
4604 const double lambda_be7 = log(2.0) / (53.22 * 86400.0);
4605 const double lambda_cs137 = log(2.0) / (30.05 * 365.25 * 86400.0);
4606 const double lambda_i131 = log(2.0) / (8.02 * 86400.0);
4607 const double lambda_xe133 = log(2.0) / (5.2474 * 86400.0);
4608
4609 /* Loop over particles... */
4610 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,atm)") {
4611
4612 /* Set timestep... */
4613 const double dt = cache->dt[ip];
4614
4615 /* Loss for Pb-210... */
4616 if (ctl->qnt_Apb210 >= 0)
4617 atm->q[ctl->qnt_Apb210][ip] *= exp(-dt * lambda_pb210);
4618
4619 /* Loss for Rn-222... */
4620 if (ctl->qnt_Arn222 >= 0) {
4621 const double old = atm->q[ctl->qnt_Arn222][ip];
4622 const double aux = exp(-dt * lambda_rn222);
4623 const double lost = old * (1.0 - aux);
4624 atm->q[ctl->qnt_Arn222][ip] = old * aux;
4625
4626 /* Parent-daughter process for Pb-210... */
4627 if (ctl->qnt_Apb210 >= 0)
4628 atm->q[ctl->qnt_Apb210][ip] += lost * lambda_pb210 / lambda_rn222;
4629 }
4630
4631 /* Loss for Be-7... */
4632 if (ctl->qnt_Abe7 >= 0)
4633 atm->q[ctl->qnt_Abe7][ip] *= exp(-dt * lambda_be7);
4634
4635 /* Loss for Cs-137... */
4636 if (ctl->qnt_Acs137 >= 0)
4637 atm->q[ctl->qnt_Acs137][ip] *= exp(-dt * lambda_cs137);
4638
4639 /* Loss for I-131... */
4640 if (ctl->qnt_Ai131 >= 0)
4641 atm->q[ctl->qnt_Ai131][ip] *= exp(-dt * lambda_i131);
4642
4643 /* Loss for Xe-133... */
4644 if (ctl->qnt_Axe133 >= 0)
4645 atm->q[ctl->qnt_Axe133][ip] *= exp(-dt * lambda_xe133);
4646 }
4647}

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

4652 {
4653
4654 /* Initialize GSL random number generators... */
4655 gsl_rng_env_setup();
4656 if (omp_get_max_threads() > NTHREADS)
4657 ERRMSG("Too many threads!");
4658 for (int i = 0; i < NTHREADS; i++) {
4659 rng[i] = gsl_rng_alloc(gsl_rng_default);
4660 gsl_rng_set(rng[i], gsl_rng_default_seed
4661 + (long unsigned) (ntask * NTHREADS + i));
4662 }
4663
4664 /* Initialize cuRAND random number generators... */
4665#ifdef CURAND
4666 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
4667 CURAND_STATUS_SUCCESS)
4668 ERRMSG("Cannot create random number generator!");
4669 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
4670 CURAND_STATUS_SUCCESS)
4671 ERRMSG("Cannot set seed for random number generator!");
4672 if (curandSetStream
4673 (rng_curand,
4674 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
4675 CURAND_STATUS_SUCCESS)
4676 ERRMSG("Cannot set stream for random number generator!");
4677#endif
4678}
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:333

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

4686 {
4687
4688 /* Use GSL random number generators... */
4689 if (ctl->rng_type == 0) {
4690
4691 /* Uniform distribution... */
4692 if (method == 0) {
4693#pragma omp parallel for default(shared)
4694 for (size_t i = 0; i < n; ++i)
4695 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
4696 }
4697
4698 /* Normal distribution... */
4699 else if (method == 1) {
4700#pragma omp parallel for default(shared)
4701 for (size_t i = 0; i < n; ++i)
4702 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
4703 }
4704
4705 /* Update of random numbers on device... */
4706#ifdef _OPENACC
4707 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
4708#pragma acc update device(rs[:n])
4709#endif
4710 }
4711
4712 /* Use Squares random number generator (Widynski, 2022)... */
4713 else if (ctl->rng_type == 1) {
4714
4715 /* Set key (don't change this!)... */
4716 const uint64_t key = 0xc8e4fd154ce32f6d;
4717
4718 /* Uniform distribution... */
4719#ifdef _OPENACC
4720#pragma acc data present(rs)
4721#pragma acc parallel loop independent gang vector
4722#else
4723#pragma omp parallel for default(shared)
4724#endif
4725 for (size_t i = 0; i < n + 1; ++i) {
4726 uint64_t r, t, x, y, z;
4727 y = x = (rng_ctr + i) * key;
4728 z = y + key;
4729 x = x * x + y;
4730 x = (x >> 32) | (x << 32);
4731 x = x * x + z;
4732 x = (x >> 32) | (x << 32);
4733 x = x * x + y;
4734 x = (x >> 32) | (x << 32);
4735 t = x = x * x + z;
4736 x = (x >> 32) | (x << 32);
4737 r = t ^ ((x * x + y) >> 32);
4738 rs[i] = (double) r / (double) UINT64_MAX;
4739 }
4740 rng_ctr += n + 1;
4741
4742 /* Normal distribution... */
4743 if (method == 1) {
4744#ifdef _OPENACC
4745#pragma acc parallel loop independent gang vector
4746#else
4747#pragma omp parallel for default(shared)
4748#endif
4749 for (size_t i = 0; i < n; i += 2) {
4750 const double r = sqrt(-2.0 * log(rs[i]));
4751 const double phi = 2.0 * M_PI * rs[i + 1];
4752 rs[i] = r * cosf((float) phi);
4753 rs[i + 1] = r * sinf((float) phi);
4754 }
4755 }
4756 }
4757
4758 /* Use cuRAND random number generators... */
4759 else if (ctl->rng_type == 2) {
4760#ifdef CURAND
4761#pragma acc host_data use_device(rs)
4762 {
4763
4764 /* Uniform distribution... */
4765 if (method == 0) {
4766 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
4767 CURAND_STATUS_SUCCESS)
4768 ERRMSG("Cannot create random numbers!");
4769 }
4770
4771 /* Normal distribution... */
4772 else if (method == 1) {
4773 if (curandGenerateNormalDouble
4774 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
4775 1.0) != CURAND_STATUS_SUCCESS)
4776 ERRMSG("Cannot create random numbers!");
4777 }
4778 }
4779#else
4780 ERRMSG("MPTRAC was compiled without cuRAND!");
4781#endif
4782 }
4783}
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2670

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

4792 {
4793
4794 /* Set timer... */
4795 SELECT_TIMER("MODULE_SEDI", "PHYSICS");
4796
4797 /* Loop over particles... */
4798 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4799
4800 /* Get temperature... */
4801 double t;
4803 INTPOL_3D(t, 1);
4804
4805 /* Sedimentation velocity... */
4806 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4807 atm->q[ctl->qnt_rhop][ip]);
4808
4809 /* Calculate pressure change... */
4810 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
4811 }
4812}
Here is the call graph for this function:

◆ module_sort()

void module_sort ( const ctl_t ctl,
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 4816 of file mptrac.c.

4819 {
4820
4821 /* Set timer... */
4822 SELECT_TIMER("MODULE_SORT", "PHYSICS");
4823
4824 /* Allocate... */
4825 const int np = atm->np;
4826 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
4827 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
4828 if (a == NULL || p == NULL)
4829 ERRMSG("Out of memory!");
4830
4831#ifdef _OPENACC
4832#pragma acc enter data create(a[0:np],p[0:np])
4833#pragma acc data present(ctl,met0,atm,a,p)
4834#endif
4835
4836 /* Get box index... */
4837#ifdef _OPENACC
4838#pragma acc parallel loop independent gang vector
4839#else
4840#pragma omp parallel for default(shared)
4841#endif
4842 for (int ip = 0; ip < np; ip++) {
4843 a[ip] =
4844 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
4845 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
4846 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
4847 p[ip] = ip;
4848 }
4849
4850 /* Sorting... */
4851#ifdef THRUST
4852#ifdef _OPENACC
4853#pragma acc host_data use_device(a,p)
4854#endif
4855 thrustSortWrapper(a, np, p);
4856#else
4857#ifdef _OPENACC
4858 ERRMSG("GSL sort fallback not available on GPU, use THRUST!");
4859#endif
4860 gsl_sort_index((size_t *) p, a, 1, (size_t) np);
4861#endif
4862
4863 /* Sort data... */
4864 module_sort_help(atm->time, p, np);
4865 module_sort_help(atm->p, p, np);
4866 module_sort_help(atm->lon, p, np);
4867 module_sort_help(atm->lat, p, np);
4868 for (int iq = 0; iq < ctl->nq; iq++)
4869 module_sort_help(atm->q[iq], p, np);
4870
4871 /* Free... */
4872#ifdef _OPENACC
4873#pragma acc exit data delete(a,p)
4874#endif
4875 free(a);
4876 free(p);
4877}
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:4881
int nq
Number of quantities.
Definition: mptrac.h:2138
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 4881 of file mptrac.c.

4884 {
4885
4886 /* Allocate... */
4887 double *restrict const help =
4888 (double *) malloc((size_t) np * sizeof(double));
4889 if (help == NULL)
4890 ERRMSG("Out of memory!");
4891
4892 /* Reordering of array... */
4893#ifdef _OPENACC
4894#pragma acc enter data create(help[0:np])
4895#pragma acc data present(a,p,help)
4896#pragma acc parallel loop independent gang vector
4897#else
4898#pragma omp parallel for default(shared)
4899#endif
4900 for (int ip = 0; ip < np; ip++)
4901 help[ip] = a[p[ip]];
4902#ifdef _OPENACC
4903#pragma acc parallel loop independent gang vector
4904#else
4905#pragma omp parallel for default(shared)
4906#endif
4907 for (int ip = 0; ip < np; ip++)
4908 a[ip] = help[ip];
4909
4910 /* Free... */
4911#ifdef _OPENACC
4912#pragma acc exit data delete(help)
4913#endif
4914 free(help);
4915}

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

4924 {
4925
4926 /* Set timer... */
4927 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS");
4928
4929 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
4930 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
4931
4932 const int local =
4933 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
4934
4935 /* Loop over particles... */
4936 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
4937
4938 /* Set time step for each air parcel... */
4939 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
4940 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
4941 && ctl->direction * (atm->time[ip] - t) < 0))
4942 cache->dt[ip] = t - atm->time[ip];
4943 else
4944 cache->dt[ip] = 0.0;
4945
4946 /* Check horizontal boundaries of local meteo data... */
4947#ifndef DD
4948 int dd = 1;
4949#else
4950 int dd = 0;
4951#endif
4952 if (dd) {
4953 if (local && (atm->lon[ip] <= met0->lon[0]
4954 || atm->lon[ip] >= met0->lon[met0->nx - 1]
4955 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
4956 cache->dt[ip] = 0.0;
4957 } else {
4958 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
4959 cache->dt[ip] = 0;
4960 }
4961 }
4962}
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2459
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2465
int qnt_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2453
double t_start
Start time of simulation [s].
Definition: mptrac.h:2462

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

4968 {
4969
4970 /* Set timer... */
4971 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS");
4972
4973 /* Set start time... */
4974 if (ctl->direction == 1) {
4975 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4976 if (ctl->t_stop > 1e99)
4977 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4978 } else {
4979 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4980 if (ctl->t_stop > 1e99)
4981 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4982 }
4983
4984 /* Check time interval... */
4985 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4986 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4987
4988 /* Round start time... */
4989 if (ctl->direction == 1)
4990 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4991 else
4992 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4993}

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

5003 {
5004
5005 /* Set timer... */
5006 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS");
5007
5008 /* Loop over particles... */
5009 PARTICLE_LOOP(0, atm->np, 1,
5010 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5011
5012 /* Get temperature... */
5013 double t;
5015 INTPOL_3D(t, 1);
5016
5017 /* Get molecular density... */
5018 const double M = MOLEC_DENS(atm->p[ip], t);
5019
5020 /* Get total column ozone... */
5021 double o3c;
5022 INTPOL_2D(o3c, 1);
5023
5024 /* Get solar zenith angle... */
5025 const double sza =
5026 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
5027
5028 /* Get O(1D) volume mixing ratio... */
5029 const double o1d =
5030 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
5031
5032 /* Reactions for CFC-10... */
5033 if (ctl->qnt_Cccl4 >= 0) {
5034 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
5035 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
5036 atm->p[ip], sza, o3c);
5037 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5038 }
5039
5040 /* Reactions for CFC-11... */
5041 if (ctl->qnt_Cccl3f >= 0) {
5042 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
5043 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
5044 atm->p[ip], sza, o3c);
5045 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5046 }
5047
5048 /* Reactions for CFC-12... */
5049 if (ctl->qnt_Cccl2f2 >= 0) {
5050 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
5051 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
5052 atm->p[ip], sza, o3c);
5053 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5054 }
5055
5056 /* Reactions for N2O... */
5057 if (ctl->qnt_Cn2o >= 0) {
5058 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
5059 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
5060 atm->p[ip], sza, o3c);
5061 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5062 }
5063 }
5064}
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:483
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3302
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3299
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3293
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3296
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3398
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 5068 of file mptrac.c.

5073 {
5074
5075 /* Set timer... */
5076 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS");
5077
5078 /* Check quantity flags... */
5079 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5080 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5081
5082 /* Loop over particles... */
5083 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5084
5085 /* Check whether particle is below cloud top... */
5086 double pct;
5088 INTPOL_2D(pct, 1);
5089 if (!isfinite(pct) || atm->p[ip] <= pct)
5090 continue;
5091
5092 /* Get cloud bottom pressure... */
5093 double pcb;
5094 INTPOL_2D(pcb, 0);
5095
5096 /* Estimate precipitation rate (Pisso et al., 2019)... */
5097 double cl;
5098 INTPOL_2D(cl, 0);
5099 const double Is =
5100 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
5101 if (Is < 0.01)
5102 continue;
5103
5104 /* Check whether particle is inside or below cloud... */
5105 double lwc, rwc, iwc, swc;
5106 INTPOL_3D(lwc, 1);
5107 INTPOL_3D(rwc, 0);
5108 INTPOL_3D(iwc, 0);
5109 INTPOL_3D(swc, 0);
5110 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
5111
5112 /* Get temperature... */
5113 double t;
5114 INTPOL_3D(t, 0);
5115
5116 /* Calculate in-cloud scavenging coefficient... */
5117 double lambda = 0;
5118 if (inside) {
5119
5120 /* Calculate retention factor... */
5121 double eta;
5122 if (t > 273.15)
5123 eta = 1;
5124 else if (t <= 238.15)
5125 eta = ctl->wet_depo_ic_ret_ratio;
5126 else
5127 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
5128
5129 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5130 if (ctl->wet_depo_ic_a > 0)
5131 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
5132
5133 /* Use Henry's law for gases... */
5134 else if (ctl->wet_depo_ic_h[0] > 0) {
5135
5136 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5137 double h = ctl->wet_depo_ic_h[0]
5138 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
5139
5140 /* Use effective Henry's constant for SO2
5141 (Berglen, 2004; Simpson, 2012)... */
5142 if (ctl->wet_depo_so2_ph > 0) {
5143 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
5144 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
5145 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
5146 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
5147 }
5148
5149 /* Estimate depth of cloud layer... */
5150 const double dz = 1e3 * (Z(pct) - Z(pcb));
5151
5152 /* Calculate scavenging coefficient... */
5153 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5154 }
5155 }
5156
5157 /* Calculate below-cloud scavenging coefficient... */
5158 else {
5159
5160 /* Calculate retention factor... */
5161 double eta;
5162 if (t > 270)
5163 eta = 1;
5164 else
5165 eta = ctl->wet_depo_bc_ret_ratio;
5166
5167 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5168 if (ctl->wet_depo_bc_a > 0)
5169 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
5170
5171 /* Use Henry's law for gases... */
5172 else if (ctl->wet_depo_bc_h[0] > 0) {
5173
5174 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5175 const double h = ctl->wet_depo_bc_h[0]
5176 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
5177
5178 /* Estimate depth of cloud layer... */
5179 const double dz = 1e3 * (Z(pct) - Z(pcb));
5180
5181 /* Calculate scavenging coefficient... */
5182 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5183 }
5184 }
5185
5186 /* Calculate exponential decay of mass... */
5187 const double aux = exp(-cache->dt[ip] * lambda);
5188 if (ctl->qnt_m >= 0) {
5189 if (ctl->qnt_mloss_wet >= 0)
5190 atm->q[ctl->qnt_mloss_wet][ip]
5191 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5192 atm->q[ctl->qnt_m][ip] *= aux;
5193 if (ctl->qnt_loss_rate >= 0)
5194 atm->q[ctl->qnt_loss_rate][ip] += lambda;
5195 }
5196 if (ctl->qnt_vmr >= 0)
5197 atm->q[ctl->qnt_vmr][ip] *= aux;
5198 }
5199}
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2895
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2889
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2312
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2907
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2886
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2904
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2913
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2901
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2910
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2898
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2892

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

5210 {
5211
5212 /* Initialize GPU... */
5213#ifdef _OPENACC
5214 SELECT_TIMER("ACC_INIT", "INIT");
5215 int rank = 0;
5216#ifdef MPI
5217 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5218#endif
5219 if (acc_get_num_devices(acc_device_nvidia) <= 0)
5220 ERRMSG("Not running on a GPU device!");
5221 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
5222 acc_device_nvidia);
5223 acc_device_t device_type = acc_get_device_type();
5224 acc_init(device_type);
5225#endif
5226
5227 /* Allocate... */
5228 SELECT_TIMER("ALLOC", "MEMORY");
5229 ALLOC(*ctl, ctl_t, 1);
5230 ALLOC(*cache, cache_t, 1);
5231 ALLOC(*clim, clim_t, 1);
5232 ALLOC(*met0, met_t, 1);
5233 ALLOC(*met1, met_t, 1);
5234 ALLOC(*atm, atm_t, 1);
5235 ALLOC(*dd, dd_t, 1);
5236
5237 /* Create data region on GPU... */
5238#ifdef _OPENACC
5239 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY");
5240 ctl_t *ctlup = *ctl;
5241 cache_t *cacheup = *cache;
5242 clim_t *climup = *clim;
5243 met_t *met0up = *met0;
5244 met_t *met1up = *met1;
5245 atm_t *atmup = *atm;
5246#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
5247#ifdef DD
5248 dd_t *ddup = *dd;
5249#pragma acc enter data create(ddup[:1])
5250#endif
5251#endif
5252}
Air parcel data.
Definition: mptrac.h:3185
Cache data structure.
Definition: mptrac.h:3240
Climatological data.
Definition: mptrac.h:3380
Control parameters.
Definition: mptrac.h:2131
Domain decomposition data structure.
Definition: mptrac.h:3613
Meteo data structure.
Definition: mptrac.h:3439

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

5263 {
5264
5265 /* Delete data region on GPU... */
5266#ifdef _OPENACC
5267 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY");
5268#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
5269#endif
5270
5271 /* Free... */
5272 SELECT_TIMER("FREE", "MEMORY");
5273 free(atm);
5274 free(ctl);
5275 free(cache);
5276 free(clim);
5277 free(met0);
5278 free(met1);
5279
5280 /* Free MPI datatype... */
5281#ifdef DD
5282 MPI_Type_free(&dd->MPI_Particle);
5283#endif
5284 free(dd);
5285}

◆ 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_help
read_met
SELECT_TIMER
LOG
ERRMSG
WARN
Author
Lars Hoffmann

Definition at line 5289 of file mptrac.c.

5295 {
5296
5297 static int init;
5298
5299 met_t *mets;
5300
5301 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
5302
5303 /* Set timer... */
5304 SELECT_TIMER("GET_MET", "INPUT");
5305
5306 /* Init... */
5307 if (t == ctl->t_start || !init) {
5308 init = 1;
5309
5310 /* Read meteo data... */
5311 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
5312 ctl->metbase, ctl->dt_met, filename);
5313 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5314 ERRMSG("Cannot open file!");
5315
5316 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
5317 ctl->metbase, ctl->dt_met, filename);
5318 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5319 ERRMSG("Cannot open file!");
5320
5321 /* Update GPU... */
5322 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
5323 SELECT_TIMER("GET_MET", "INPUT");
5324
5325 /* Caching... */
5326 if (ctl->met_cache && t != ctl->t_stop) {
5327 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
5328 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
5329 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5330 LOG(1, "Caching: %s", cachefile);
5331 if (system(cmd) != 0)
5332 WARN("Caching command failed!");
5333 }
5334 }
5335
5336 /* Read new data for forward trajectories... */
5337 if (t > (*met1)->time) {
5338
5339 /* Pointer swap... */
5340 mets = *met1;
5341 *met1 = *met0;
5342 *met0 = mets;
5343
5344 /* Read new meteo data... */
5345 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
5346 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5347 ERRMSG("Cannot open file!");
5348
5349 /* Update GPU... */
5350 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
5351 SELECT_TIMER("GET_MET", "INPUT");
5352
5353 /* Caching... */
5354 if (ctl->met_cache && t != ctl->t_stop) {
5355 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
5356 cachefile);
5357 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5358 LOG(1, "Caching: %s", cachefile);
5359 if (system(cmd) != 0)
5360 WARN("Caching command failed!");
5361 }
5362 }
5363
5364 /* Read new data for backward trajectories... */
5365 if (t < (*met0)->time) {
5366
5367 /* Pointer swap... */
5368 mets = *met1;
5369 *met1 = *met0;
5370 *met0 = mets;
5371
5372 /* Read new meteo data... */
5373 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
5374 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5375 ERRMSG("Cannot open file!");
5376
5377 /* Update GPU... */
5378 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
5379 SELECT_TIMER("GET_MET", "INPUT");
5380
5381 /* Caching... */
5382 if (ctl->met_cache && t != ctl->t_stop) {
5383 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
5384 cachefile);
5385 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5386 LOG(1, "Caching: %s", cachefile);
5387 if (system(cmd) != 0)
5388 WARN("Caching command failed!");
5389 }
5390 }
5391
5392 /* Check that grids are consistent... */
5393 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
5394 if ((*met0)->nx != (*met1)->nx
5395 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
5396 ERRMSG("Meteo grid dimensions do not match!");
5397 for (int ix = 0; ix < (*met0)->nx; ix++)
5398 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
5399 ERRMSG("Meteo grid longitudes do not match!");
5400 for (int iy = 0; iy < (*met0)->ny; iy++)
5401 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
5402 ERRMSG("Meteo grid latitudes do not match!");
5403 for (int ip = 0; ip < (*met0)->np; ip++)
5404 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
5405 ERRMSG("Meteo grid pressure levels do not match!");
5406 }
5407}
void get_met_help(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:1968
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:6467
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2010
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2643
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2475
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 5411 of file mptrac.c.

5416 {
5417
5418 /* Initialize timesteps... */
5419 module_timesteps_init(ctl, atm);
5420
5421 /* Initialize random number generator... */
5422 module_rng_init(ntask);
5423
5424 /* Update GPU memory... */
5425 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
5426}
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4966
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:4651
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 5430 of file mptrac.c.

5433 {
5434
5435 int result;
5436
5437 /* Set timer... */
5438 SELECT_TIMER("READ_ATM", "INPUT");
5439
5440 /* Init... */
5441 atm->np = 0;
5442
5443 /* Write info... */
5444 LOG(1, "Read atmospheric data: %s", filename);
5445
5446 /* Read ASCII data... */
5447 if (ctl->atm_type == 0)
5448 result = read_atm_asc(filename, ctl, atm);
5449
5450 /* Read binary data... */
5451 else if (ctl->atm_type == 1)
5452 result = read_atm_bin(filename, ctl, atm);
5453
5454 /* Read netCDF data... */
5455 else if (ctl->atm_type == 2)
5456 result = read_atm_nc(filename, ctl, atm);
5457
5458 /* Read CLaMS data... */
5459 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
5460 result = read_atm_clams(filename, ctl, atm);
5461
5462 /* Error... */
5463 else
5464 ERRMSG("Atmospheric data type not supported!");
5465
5466 /* Check result... */
5467 if (result != 1)
5468 return 0;
5469
5470 /* Check number of air parcels... */
5471 if (atm->np < 1)
5472 ERRMSG("Can not read any data!");
5473
5474 /* Write info... */
5475 double mini, maxi;
5476 LOG(2, "Number of particles: %d", atm->np);
5477 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5478 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5479 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5480 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5481 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5482 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5483 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5484 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5485 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5486 for (int iq = 0; iq < ctl->nq; iq++) {
5487 char msg[5 * LEN];
5488 sprintf(msg, "Quantity %s range: %s ... %s %s",
5489 ctl->qnt_name[iq], ctl->qnt_format[iq],
5490 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5491 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5492 LOG(2, msg, mini, maxi);
5493 }
5494
5495 /* Return success... */
5496 return 1;
5497}
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:7239
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:7123
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:7179
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:7081
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2150
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:2948
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2147
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2141
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 5501 of file mptrac.c.

5503 {
5504
5505 /* Set timer... */
5506 SELECT_TIMER("READ_CLIM", "INPUT");
5507
5508 /* Init tropopause climatology... */
5509 clim_tropo_init(clim);
5510
5511 /* Read photolysis rates... */
5512 if (ctl->clim_photo[0] != '-')
5513 read_clim_photo(ctl->clim_photo, &clim->photo);
5514
5515 /* Read HNO3 climatology... */
5516 if (ctl->clim_hno3_filename[0] != '-')
5517 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
5518
5519 /* Read OH climatology... */
5520 if (ctl->clim_oh_filename[0] != '-') {
5521 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
5522 if (ctl->oh_chem_beta > 0)
5523 clim_oh_diurnal_correction(ctl, clim);
5524 }
5525
5526 /* Read H2O2 climatology... */
5527 if (ctl->clim_h2o2_filename[0] != '-')
5528 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
5529
5530 /* Read HO2 climatology... */
5531 if (ctl->clim_ho2_filename[0] != '-')
5532 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
5533
5534 /* Read O(1D) climatology... */
5535 if (ctl->clim_o1d_filename[0] != '-')
5536 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
5537
5538 /* Read CFC-10 time series... */
5539 if (ctl->clim_ccl4_timeseries[0] != '-')
5541
5542 /* Read CFC-11 time series... */
5543 if (ctl->clim_ccl3f_timeseries[0] != '-')
5545
5546 /* Read CFC-12 time series... */
5547 if (ctl->clim_ccl2f2_timeseries[0] != '-')
5549
5550 /* Read N2O time series... */
5551 if (ctl->clim_n2o_timeseries[0] != '-')
5552 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
5553
5554 /* Read SF6 time series... */
5555 if (ctl->clim_sf6_timeseries[0] != '-')
5556 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
5557}
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:7272
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:7391
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:7445
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:2775
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2778
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2763
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2772
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2769
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2766
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 5561 of file mptrac.c.

5565 {
5566
5567 /* Set timer... */
5568 SELECT_TIMER("READ_CTL", "INPUT");
5569
5570 /* Write info... */
5571 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
5572 "(executable: %s | version: %s | compiled: %s, %s)\n",
5573 argv[0], VERSION, __DATE__, __TIME__);
5574
5575 /* Initialize quantity indices... */
5576 ctl->qnt_idx = -1;
5577 ctl->qnt_ens = -1;
5578 ctl->qnt_stat = -1;
5579 ctl->qnt_m = -1;
5580 ctl->qnt_vmr = -1;
5581 ctl->qnt_rp = -1;
5582 ctl->qnt_rhop = -1;
5583 ctl->qnt_ps = -1;
5584 ctl->qnt_ts = -1;
5585 ctl->qnt_zs = -1;
5586 ctl->qnt_us = -1;
5587 ctl->qnt_vs = -1;
5588 ctl->qnt_ess = -1;
5589 ctl->qnt_nss = -1;
5590 ctl->qnt_shf = -1;
5591 ctl->qnt_lsm = -1;
5592 ctl->qnt_sst = -1;
5593 ctl->qnt_pbl = -1;
5594 ctl->qnt_pt = -1;
5595 ctl->qnt_tt = -1;
5596 ctl->qnt_zt = -1;
5597 ctl->qnt_h2ot = -1;
5598 ctl->qnt_zg = -1;
5599 ctl->qnt_p = -1;
5600 ctl->qnt_t = -1;
5601 ctl->qnt_rho = -1;
5602 ctl->qnt_u = -1;
5603 ctl->qnt_v = -1;
5604 ctl->qnt_w = -1;
5605 ctl->qnt_h2o = -1;
5606 ctl->qnt_o3 = -1;
5607 ctl->qnt_lwc = -1;
5608 ctl->qnt_rwc = -1;
5609 ctl->qnt_iwc = -1;
5610 ctl->qnt_swc = -1;
5611 ctl->qnt_cc = -1;
5612 ctl->qnt_pct = -1;
5613 ctl->qnt_pcb = -1;
5614 ctl->qnt_cl = -1;
5615 ctl->qnt_plcl = -1;
5616 ctl->qnt_plfc = -1;
5617 ctl->qnt_pel = -1;
5618 ctl->qnt_cape = -1;
5619 ctl->qnt_cin = -1;
5620 ctl->qnt_o3c = -1;
5621 ctl->qnt_hno3 = -1;
5622 ctl->qnt_oh = -1;
5623 ctl->qnt_h2o2 = -1;
5624 ctl->qnt_ho2 = -1;
5625 ctl->qnt_o1d = -1;
5626 ctl->qnt_mloss_oh = -1;
5627 ctl->qnt_mloss_h2o2 = -1;
5628 ctl->qnt_mloss_kpp = -1;
5629 ctl->qnt_mloss_wet = -1;
5630 ctl->qnt_mloss_dry = -1;
5631 ctl->qnt_mloss_decay = -1;
5632 ctl->qnt_loss_rate = -1;
5633 ctl->qnt_psat = -1;
5634 ctl->qnt_psice = -1;
5635 ctl->qnt_pw = -1;
5636 ctl->qnt_sh = -1;
5637 ctl->qnt_rh = -1;
5638 ctl->qnt_rhice = -1;
5639 ctl->qnt_theta = -1;
5640 ctl->qnt_zeta = -1;
5641 ctl->qnt_zeta_d = -1;
5642 ctl->qnt_zeta_dot = -1;
5643 ctl->qnt_eta = -1;
5644 ctl->qnt_eta_dot = -1;
5645 ctl->qnt_tvirt = -1;
5646 ctl->qnt_lapse = -1;
5647 ctl->qnt_vh = -1;
5648 ctl->qnt_vz = -1;
5649 ctl->qnt_pv = -1;
5650 ctl->qnt_tdew = -1;
5651 ctl->qnt_tice = -1;
5652 ctl->qnt_tsts = -1;
5653 ctl->qnt_tnat = -1;
5654 ctl->qnt_Cx = -1;
5655 ctl->qnt_Ch2o = -1;
5656 ctl->qnt_Co3 = -1;
5657 ctl->qnt_Cco = -1;
5658 ctl->qnt_Coh = -1;
5659 ctl->qnt_Ch = -1;
5660 ctl->qnt_Cho2 = -1;
5661 ctl->qnt_Ch2o2 = -1;
5662 ctl->qnt_Co1d = -1;
5663 ctl->qnt_Co3p = -1;
5664 ctl->qnt_Cccl4 = -1;
5665 ctl->qnt_Cccl3f = -1;
5666 ctl->qnt_Cccl2f2 = -1;
5667 ctl->qnt_Cn2o = -1;
5668 ctl->qnt_Csf6 = -1;
5669 ctl->qnt_aoa = -1;
5670 ctl->qnt_Arn222 = -1;
5671 ctl->qnt_Apb210 = -1;
5672 ctl->qnt_Abe7 = -1;
5673 ctl->qnt_Acs137 = -1;
5674 ctl->qnt_Ai131 = -1;
5675 ctl->qnt_Axe133 = -1;
5676 ctl->qnt_subdomain = -1;
5677 ctl->qnt_destination = -1;
5678
5679 /* Read quantities... */
5680 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
5681 if (ctl->nq > NQ)
5682 ERRMSG("Too many quantities!");
5683 for (int iq = 0; iq < ctl->nq; iq++) {
5684
5685 /* Read quantity name and format... */
5686 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
5687 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
5688 ctl->qnt_longname[iq]);
5689 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
5690 ctl->qnt_format[iq]);
5691 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
5692 sprintf(ctl->qnt_format[iq], "%%.2f");
5693
5694 /* Try to identify quantity... */
5695 SET_QNT(qnt_idx, "idx", "particle index", "-")
5696 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
5697 SET_QNT(qnt_stat, "stat", "station flag", "-")
5698 SET_QNT(qnt_m, "m", "mass", "kg")
5699 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
5700 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
5701 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
5702 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
5703 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
5704 SET_QNT(qnt_zs, "zs", "surface height", "km")
5705 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
5706 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
5707 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
5708 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
5709 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
5710 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
5711 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
5712 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
5713 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
5714 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
5715 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
5716 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
5717 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
5718 SET_QNT(qnt_p, "p", "pressure", "hPa")
5719 SET_QNT(qnt_t, "t", "temperature", "K")
5720 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
5721 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
5722 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
5723 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
5724 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
5725 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
5726 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
5727 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
5728 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
5729 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
5730 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
5731 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
5732 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
5733 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
5734 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
5735 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
5736 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
5737 SET_QNT(qnt_cape, "cape", "convective available potential energy",
5738 "J/kg")
5739 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
5740 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
5741 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
5742 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
5743 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
5744 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
5745 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
5746 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
5747 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
5748 "mass loss due to H2O2 chemistry", "kg")
5749 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
5750 "kg")
5751 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
5752 "kg")
5753 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
5754 "kg")
5755 SET_QNT(qnt_mloss_decay, "mloss_decay",
5756 "mass loss due to exponential decay", "kg")
5757 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
5758 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
5759 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
5760 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
5761 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
5762 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
5763 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
5764 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
5765 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
5766 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
5767 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
5768 "K/day")
5769 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
5770 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
5771 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
5772 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
5773 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
5774 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
5775 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
5776 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
5777 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
5778 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
5779 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
5780 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
5781 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
5782 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
5783 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
5784 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
5785 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
5786 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
5787 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
5788 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
5789 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
5790 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
5791 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
5792 "ppv")
5793 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
5794 "ppv")
5795 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
5796 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
5797 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
5798 SET_QNT(qnt_Arn222, "Arn222", "Rn-222 activity", "Bq")
5799 SET_QNT(qnt_Apb210, "Apb210", "Pb-210 activity", "Bq")
5800 SET_QNT(qnt_Abe7, "Abe7", "Be-7 activity", "Bq")
5801 SET_QNT(qnt_Acs137, "Acs137", "Cs-137 activity", "Bq")
5802 SET_QNT(qnt_Ai131, "Ai131", "I-131 activity", "Bq")
5803 SET_QNT(qnt_Axe133, "Axe133", "Xe-133 activity", "Bq")
5804 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
5805 SET_QNT(qnt_destination, "destination",
5806 "subdomain index of destination", "-")
5807 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
5808 }
5809
5810 /* Vertical coordinate and velocity... */
5811 ctl->advect_vert_coord =
5812 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
5813 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
5814 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
5815
5816 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
5817 ERRMSG("Add quantity zeta for diabatic advection!");
5818 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
5819 ERRMSG("Add quantity eta for etadot avection!");
5820
5821 ctl->met_vert_coord =
5822 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
5823 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
5824 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
5825
5826 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
5827 ERRMSG
5828 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
5829 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
5830 ERRMSG
5831 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
5832
5833 /* Time steps of simulation... */
5834 ctl->direction =
5835 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
5836 if (ctl->direction != -1 && ctl->direction != 1)
5837 ERRMSG("Set DIRECTION to -1 or 1!");
5838 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
5839 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
5840
5841 /* Meteo data... */
5842 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
5843 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
5844 ctl->met_convention =
5845 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
5846 ctl->met_type =
5847 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
5848 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
5849 ERRMSG
5850 ("Please use meteo files in netcdf format for diabatic calculations.");
5851 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
5852 ERRMSG
5853 ("Please use meteo files in netcdf format for etadot calculations.");
5854 ctl->met_clams =
5855 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
5856 ctl->met_nc_scale =
5857 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
5858 ctl->met_nc_level =
5859 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
5860 ctl->met_nc_quant =
5861 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
5862 ctl->met_zstd_level =
5863 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
5864 for (int i = 0; i < METVAR; i++) {
5865 char defprec[LEN] = "0", deftol[LEN] = "0.0";
5866 if (i == 0) /* geopotential height */
5867 sprintf(deftol, "0.5");
5868 else if (i == 1) /* temperature */
5869 sprintf(deftol, "5.0");
5870 else /* other variables */
5871 sprintf(defprec, "8");
5872 ctl->met_comp_prec[i] =
5873 (int) scan_ctl(filename, argc, argv, "MET_COMP_PREC", i, defprec, NULL);
5874 ctl->met_comp_tol[i] =
5875 scan_ctl(filename, argc, argv, "MET_COMP_TOL", i, deftol, NULL);
5876 }
5877 ctl->met_cms_batch =
5878 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
5879 ctl->met_cms_zstd =
5880 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
5881 ctl->met_cms_nd0x =
5882 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
5883 ctl->met_cms_nd0y =
5884 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
5885 ctl->met_cms_maxlev =
5886 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
5887 ctl->met_cms_eps_z =
5888 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
5889 ctl->met_cms_eps_t =
5890 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
5891 ctl->met_cms_eps_u =
5892 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
5893 ctl->met_cms_eps_v =
5894 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
5895 ctl->met_cms_eps_w =
5896 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
5897 ctl->met_cms_eps_pv =
5898 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
5899 ctl->met_cms_eps_h2o =
5900 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
5901 ctl->met_cms_eps_o3 =
5902 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5903 ctl->met_cms_eps_lwc =
5904 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5905 ctl->met_cms_eps_rwc =
5906 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5907 ctl->met_cms_eps_iwc =
5908 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5909 ctl->met_cms_eps_swc =
5910 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5911 ctl->met_cms_eps_cc =
5912 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5913 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5914 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5915 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5916 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5917 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5918 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5919 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5920 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5921 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5922 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5923 ctl->met_detrend =
5924 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5925 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5926 if (ctl->met_np > EP)
5927 ERRMSG("Too many pressure levels!");
5928 ctl->met_press_level_def =
5929 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5930 NULL);
5931 if (ctl->met_press_level_def >= 0) {
5932 level_definitions(ctl);
5933 } else {
5934 if (ctl->met_np > 0) {
5935 for (int ip = 0; ip < ctl->met_np; ip++)
5936 ctl->met_p[ip] =
5937 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5938 }
5939 }
5940 ctl->met_nlev =
5941 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
5942 if (ctl->met_nlev > EP)
5943 ERRMSG("Too many model levels!");
5944 for (int ip = 0; ip < ctl->met_nlev; ip++)
5945 ctl->met_lev_hyam[ip] =
5946 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
5947 for (int ip = 0; ip < ctl->met_nlev; ip++)
5948 ctl->met_lev_hybm[ip] =
5949 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
5950 ctl->met_geopot_sx =
5951 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5952 ctl->met_geopot_sy =
5953 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5954 ctl->met_relhum =
5955 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5956 ctl->met_cape =
5957 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
5958 if (ctl->met_cape < 0 || ctl->met_cape > 1)
5959 ERRMSG("Set MET_CAPE to 0 or 1!");
5960 ctl->met_pbl =
5961 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
5962 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
5963 ERRMSG("Set MET_PBL to 0 ... 3!");
5964 ctl->met_pbl_min =
5965 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
5966 ctl->met_pbl_max =
5967 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
5968 ctl->met_tropo =
5969 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5970 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5971 ERRMSG("Set MET_TROPO to 0 ... 5!");
5972 ctl->met_tropo_pv =
5973 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5974 ctl->met_tropo_theta =
5975 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5976 ctl->met_tropo_spline =
5977 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5978 ctl->met_dt_out =
5979 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5980 ctl->met_cache =
5981 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5982 ctl->met_mpi_share =
5983 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5984
5985 /* Sorting... */
5986 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5987
5988 /* Isosurface parameters... */
5989 ctl->isosurf =
5990 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5991 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5992
5993 /* Random number generator... */
5994 ctl->rng_type =
5995 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
5996 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5997 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5998
5999 /* Advection parameters... */
6000 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
6001 if (!
6002 (ctl->advect == 0 || ctl->advect == 1 || ctl->advect == 2
6003 || ctl->advect == 4))
6004 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
6005
6006 /* Diffusion parameters... */
6007 ctl->diffusion
6008 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
6009 if (ctl->diffusion < 0 || ctl->diffusion > 2)
6010 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
6011 ctl->turb_dx_pbl =
6012 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
6013 ctl->turb_dx_trop =
6014 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
6015 ctl->turb_dx_strat =
6016 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
6017 ctl->turb_dz_pbl =
6018 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
6019 ctl->turb_dz_trop =
6020 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
6021 ctl->turb_dz_strat =
6022 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
6023 ctl->turb_mesox =
6024 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
6025 ctl->turb_mesoz =
6026 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
6027
6028 /* Convection... */
6029 ctl->conv_mix_pbl
6030 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
6031 ctl->conv_pbl_trans
6032 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
6033 ctl->conv_cape
6034 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
6035 ctl->conv_cin
6036 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
6037 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
6038
6039 /* Boundary conditions... */
6040 ctl->bound_mass =
6041 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
6042 ctl->bound_mass_trend =
6043 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
6044 ctl->bound_vmr =
6045 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
6046 ctl->bound_vmr_trend =
6047 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
6048 ctl->bound_lat0 =
6049 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
6050 ctl->bound_lat1 =
6051 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
6052 ctl->bound_p0 =
6053 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
6054 ctl->bound_p1 =
6055 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
6056 ctl->bound_dps =
6057 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
6058 ctl->bound_dzs =
6059 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
6060 ctl->bound_zetas =
6061 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
6062 ctl->bound_pbl =
6063 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
6064
6065 /* Species parameters... */
6066 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
6067 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
6068 ctl->molmass = 120.907;
6069 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
6070 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
6071 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
6072 ctl->molmass = 137.359;
6073 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
6074 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
6075 } else if (strcasecmp(ctl->species, "CH4") == 0) {
6076 ctl->molmass = 16.043;
6077 ctl->oh_chem_reaction = 2;
6078 ctl->oh_chem[0] = 2.45e-12;
6079 ctl->oh_chem[1] = 1775;
6080 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
6081 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6082 } else if (strcasecmp(ctl->species, "CO") == 0) {
6083 ctl->molmass = 28.01;
6084 ctl->oh_chem_reaction = 3;
6085 ctl->oh_chem[0] = 6.9e-33;
6086 ctl->oh_chem[1] = 2.1;
6087 ctl->oh_chem[2] = 1.1e-12;
6088 ctl->oh_chem[3] = -1.3;
6089 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
6090 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
6091 } else if (strcasecmp(ctl->species, "CO2") == 0) {
6092 ctl->molmass = 44.009;
6093 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
6094 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6095 } else if (strcasecmp(ctl->species, "H2O") == 0) {
6096 ctl->molmass = 18.01528;
6097 } else if (strcasecmp(ctl->species, "N2O") == 0) {
6098 ctl->molmass = 44.013;
6099 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
6100 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
6101 } else if (strcasecmp(ctl->species, "NH3") == 0) {
6102 ctl->molmass = 17.031;
6103 ctl->oh_chem_reaction = 2;
6104 ctl->oh_chem[0] = 1.7e-12;
6105 ctl->oh_chem[1] = 710;
6106 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
6107 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
6108 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
6109 ctl->molmass = 63.012;
6110 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
6111 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
6112 } else if (strcasecmp(ctl->species, "NO") == 0) {
6113 ctl->molmass = 30.006;
6114 ctl->oh_chem_reaction = 3;
6115 ctl->oh_chem[0] = 7.1e-31;
6116 ctl->oh_chem[1] = 2.6;
6117 ctl->oh_chem[2] = 3.6e-11;
6118 ctl->oh_chem[3] = 0.1;
6119 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
6120 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6121 } else if (strcasecmp(ctl->species, "NO2") == 0) {
6122 ctl->molmass = 46.005;
6123 ctl->oh_chem_reaction = 3;
6124 ctl->oh_chem[0] = 1.8e-30;
6125 ctl->oh_chem[1] = 3.0;
6126 ctl->oh_chem[2] = 2.8e-11;
6127 ctl->oh_chem[3] = 0.0;
6128 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
6129 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6130 } else if (strcasecmp(ctl->species, "O3") == 0) {
6131 ctl->molmass = 47.997;
6132 ctl->oh_chem_reaction = 2;
6133 ctl->oh_chem[0] = 1.7e-12;
6134 ctl->oh_chem[1] = 940;
6135 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
6136 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
6137 } else if (strcasecmp(ctl->species, "SF6") == 0) {
6138 ctl->molmass = 146.048;
6139 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
6140 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
6141 } else if (strcasecmp(ctl->species, "SO2") == 0) {
6142 ctl->molmass = 64.066;
6143 ctl->oh_chem_reaction = 3;
6144 ctl->oh_chem[0] = 2.9e-31;
6145 ctl->oh_chem[1] = 4.1;
6146 ctl->oh_chem[2] = 1.7e-12;
6147 ctl->oh_chem[3] = -0.2;
6148 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
6149 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
6150 }
6151
6152 /* Molar mass... */
6153 char defstr[LEN];
6154 sprintf(defstr, "%g", ctl->molmass);
6155 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
6156
6157 /* OH chemistry... */
6158 sprintf(defstr, "%d", ctl->oh_chem_reaction);
6159 ctl->oh_chem_reaction =
6160 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
6161 NULL);
6162 for (int ip = 0; ip < 4; ip++) {
6163 sprintf(defstr, "%g", ctl->oh_chem[ip]);
6164 ctl->oh_chem[ip] =
6165 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
6166 }
6167 ctl->oh_chem_beta =
6168 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
6169
6170 /* H2O2 chemistry... */
6171 ctl->h2o2_chem_reaction =
6172 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
6173
6174 /* KPP chemistry... */
6175 ctl->kpp_chem =
6176 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
6177 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
6178
6179 /* First order tracer chemistry... */
6180 ctl->tracer_chem =
6181 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
6182
6183 /* Radioactive decay... */
6184 ctl->radio_decay =
6185 (int) scan_ctl(filename, argc, argv, "RADIO_DECAY", -1, "0", NULL);
6186
6187 /* Wet deposition... */
6188 for (int ip = 0; ip < 2; ip++) {
6189 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
6190 ctl->wet_depo_ic_h[ip] =
6191 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
6192 }
6193 for (int ip = 0; ip < 1; ip++) {
6194 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
6195 ctl->wet_depo_bc_h[ip] =
6196 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
6197 }
6198 ctl->wet_depo_so2_ph =
6199 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
6200 ctl->wet_depo_ic_a =
6201 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
6202 ctl->wet_depo_ic_b =
6203 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
6204 ctl->wet_depo_bc_a =
6205 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
6206 ctl->wet_depo_bc_b =
6207 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
6208 ctl->wet_depo_pre[0] =
6209 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
6210 ctl->wet_depo_pre[1] =
6211 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
6213 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
6215 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
6216
6217 /* Dry deposition... */
6218 ctl->dry_depo_vdep =
6219 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
6220 ctl->dry_depo_dp =
6221 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
6222
6223 /* Climatological data... */
6224 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
6225 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
6226 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
6227 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
6228 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
6229 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
6230 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
6231 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
6232 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
6233 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
6234 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
6235 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
6236 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
6237 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
6238 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
6239 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
6240 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
6241 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
6242 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
6243 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
6244 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
6245 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
6246
6247 /* Mixing... */
6248 ctl->mixing_dt =
6249 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
6250 ctl->mixing_trop =
6251 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
6252 ctl->mixing_strat =
6253 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
6254 ctl->mixing_z0 =
6255 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
6256 ctl->mixing_z1 =
6257 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
6258 ctl->mixing_nz =
6259 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
6260 ctl->mixing_lon0 =
6261 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
6262 ctl->mixing_lon1 =
6263 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
6264 ctl->mixing_nx =
6265 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
6266 ctl->mixing_lat0 =
6267 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
6268 ctl->mixing_lat1 =
6269 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
6270 ctl->mixing_ny =
6271 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
6272
6273 /* Chemistry grid... */
6274 ctl->chemgrid_z0 =
6275 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
6276 ctl->chemgrid_z1 =
6277 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
6278 ctl->chemgrid_nz =
6279 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
6280 ctl->chemgrid_lon0 =
6281 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
6282 ctl->chemgrid_lon1 =
6283 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
6284 ctl->chemgrid_nx =
6285 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
6286 ctl->chemgrid_lat0 =
6287 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
6288 ctl->chemgrid_lat1 =
6289 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
6290 ctl->chemgrid_ny =
6291 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
6292
6293 /* Exponential decay... */
6294 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
6295 ctl->tdec_strat =
6296 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
6297
6298 /* PSC analysis... */
6299 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
6300 ctl->psc_hno3 =
6301 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
6302
6303 /* Output of atmospheric data... */
6304 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
6305 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
6306 ctl->atm_dt_out =
6307 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
6308 ctl->atm_filter =
6309 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
6310 ctl->atm_stride =
6311 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
6312 ctl->atm_type =
6313 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
6314 ctl->atm_type_out =
6315 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
6316 if (ctl->atm_type_out == -1)
6317 ctl->atm_type_out = ctl->atm_type;
6318 ctl->atm_nc_level =
6319 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
6320 for (int iq = 0; iq < ctl->nq; iq++)
6321 ctl->atm_nc_quant[iq] =
6322 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
6323 ctl->obs_type =
6324 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
6325
6326 /* Output of CSI data... */
6327 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
6328 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
6329 ctl->csi_dt_out =
6330 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
6331 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
6332 ctl->csi_obsmin =
6333 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
6334 ctl->csi_modmin =
6335 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
6336 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
6337 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
6338 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
6339 ctl->csi_lon0 =
6340 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
6341 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
6342 ctl->csi_nx =
6343 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
6344 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
6345 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
6346 ctl->csi_ny =
6347 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
6348
6349 /* Output of ensemble data... */
6350 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
6351 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
6352 ctl->ens_dt_out =
6353 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
6354
6355 /* Output of grid data... */
6356 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
6357 ctl->grid_basename);
6358 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
6359 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
6360 ctl->grid_dt_out =
6361 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
6362 ctl->grid_sparse =
6363 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
6364 ctl->grid_nc_level =
6365 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
6366 for (int iq = 0; iq < ctl->nq; iq++)
6367 ctl->grid_nc_quant[iq] =
6368 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
6369 ctl->grid_stddev =
6370 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
6371 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
6372 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
6373 ctl->grid_nz =
6374 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
6375 ctl->grid_lon0 =
6376 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
6377 ctl->grid_lon1 =
6378 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
6379 ctl->grid_nx =
6380 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
6381 ctl->grid_lat0 =
6382 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
6383 ctl->grid_lat1 =
6384 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
6385 ctl->grid_ny =
6386 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
6387 ctl->grid_type =
6388 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
6389
6390 /* Output of profile data... */
6391 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
6392 ctl->prof_basename);
6393 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
6394 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
6395 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
6396 ctl->prof_nz =
6397 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
6398 ctl->prof_lon0 =
6399 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
6400 ctl->prof_lon1 =
6401 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
6402 ctl->prof_nx =
6403 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
6404 ctl->prof_lat0 =
6405 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
6406 ctl->prof_lat1 =
6407 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
6408 ctl->prof_ny =
6409 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
6410
6411 /* Output of sample data... */
6412 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
6413 ctl->sample_basename);
6414 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
6415 ctl->sample_kernel);
6416 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
6417 ctl->sample_obsfile);
6418 ctl->sample_dx =
6419 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
6420 ctl->sample_dz =
6421 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
6422
6423 /* Output of station data... */
6424 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
6425 ctl->stat_basename);
6426 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
6427 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
6428 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
6429 ctl->stat_t0 =
6430 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
6431 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
6432
6433 /* Output of VTK data... */
6434 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
6435 ctl->vtk_dt_out =
6436 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
6437 ctl->vtk_stride =
6438 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
6439 ctl->vtk_scale =
6440 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
6441 ctl->vtk_offset =
6442 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
6443 ctl->vtk_sphere =
6444 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
6445
6446 /* Domain decomposition... */
6447 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
6449 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
6450 (ctl->dd == 1) ? "2" : "1", NULL);
6451 ctl->dd_subdomains_zonal =
6452 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
6453 (ctl->dd == 1) ? "2" : "1", NULL);
6455 ctl->dd = 1;
6456 else if (ctl->dd == 1)
6457 ERRMSG("Please provide zonal and meridional subdomain numbers!")
6458 ctl->dd_nbr_neighbours =
6459 (int) scan_ctl(filename, argc, argv, "DD_NBR_NEIGHBOURS", -1, "8",
6460 NULL);
6461 ctl->dd_halos_size =
6462 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
6463}
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:2647
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:11002
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:303
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:313
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1662
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3046
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2243
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3007
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:2974
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2276
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:2983
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2222
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2935
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2255
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:2977
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2264
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:2998
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2231
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3124
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2653
double stat_r
Search radius around station [km].
Definition: mptrac.h:3130
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3001
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3154
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2621
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2252
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2543
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2330
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3073
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3049
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2573
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2640
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2294
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2366
char species[LEN]
Species.
Definition: mptrac.h:2751
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:2992
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3004
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2618
double met_comp_tol[METVAR]
Compression tolerance for SZ3 or ZFP.
Definition: mptrac.h:2510
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2246
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3034
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3052
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3064
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2177
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2546
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2273
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3055
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2300
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2637
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3109
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2360
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2609
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3025
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2534
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2198
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2342
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3136
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:2968
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3070
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:2995
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2204
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3040
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2327
int radio_decay
Switch for radioactive decay module (0=off, 1=on).
Definition: mptrac.h:2883
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2606
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2579
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2174
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3076
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2180
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3079
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:2971
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2615
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:2980
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2576
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2558
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2561
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3022
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2537
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3082
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2237
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2631
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3088
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2159
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2646
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2369
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2297
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:2989
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3133
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3161
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:2953
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2519
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2597
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2877
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:2965
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2195
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2186
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3142
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2712
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3112
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2288
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3019
int met_comp_prec[METVAR]
Compression precision for SZ3 or ZFP.
Definition: mptrac.h:2507
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2216
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2336
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2564
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2624
int met_dx
Stride for longitudes.
Definition: mptrac.h:2567
int qnt_destination
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2456
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2348
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2880
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2673
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2219
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3151
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2234
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2291
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2240
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3097
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2339
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2228
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3118
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:2962
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3037
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2552
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2183
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2528
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3058
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2932
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2207
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2267
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3085
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2600
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2225
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:2941
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2874
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3013
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:2986
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2363
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3127
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3061
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2585
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2531
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2279
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2522
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2285
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3043
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2192
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3016
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3106
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:2944
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2612
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2938
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3103
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2513
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2922
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2582
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3091
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2261
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2309
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2324
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2603
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3100
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2282
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2925
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3094
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2555
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2871
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2959
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2549
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2516
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2525
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3031
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3139
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2210
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2799
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3148
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2540
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2372
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2201
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2956
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2333
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2189
int met_dy
Stride for latitudes.
Definition: mptrac.h:2570
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3164
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2153
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2634
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2249
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2144
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3115
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3145
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3121
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3067
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3167
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2213
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2258
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2270
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3028
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2375
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 6467 of file mptrac.c.

6472 {
6473
6474 /* Write info... */
6475 LOG(1, "Read meteo data: %s", filename);
6476
6477 /* Set rank... */
6478 int rank = 0;
6479#ifdef MPI
6480 if (ctl->met_mpi_share)
6481 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
6482#endif
6483
6484 /* Check rank... */
6485 if (!ctl->met_mpi_share || rank == 0) {
6486
6487 /* Read netCDF data... */
6488 if (ctl->met_type == 0) {
6489 if (read_met_nc(filename, ctl, met, dd) != 1)
6490 return 0;
6491 }
6492
6493 /* Read binary data... */
6494 else if ((ctl->met_type >= 1 && ctl->met_type <= 5) || ctl->met_type == 7) {
6495 if (read_met_bin(filename, ctl, met) != 1)
6496 return 0;
6497 }
6498
6499#ifdef ECCODES
6500 /* Read grib data... */
6501 else if (ctl->met_type == 6) {
6502 if (read_met_grib(filename, ctl, met) != 1)
6503 return 0;
6504 }
6505#endif
6506
6507 /* Not implemented... */
6508 else
6509 ERRMSG("MET_TYPE not implemented!");
6510
6511 /* Preprocessing for netCDF and grib files... */
6512 if (ctl->met_type == 0 || ctl->met_type == 6) {
6513
6514 /* Extrapolate data for lower boundary... */
6516
6517 /* Fix polar winds... */
6519
6520 /* Create periodic boundary conditions... */
6521#ifndef DD
6522 read_met_periodic(met);
6523#endif
6524
6525 /* Downsampling... */
6526 read_met_sample(ctl, met);
6527
6528 /* Calculate geopotential heights... */
6529 read_met_geopot(ctl, met);
6530
6531 /* Calculate potential vorticity... */
6532 read_met_pv(met);
6533
6534 /* Calculate boundary layer data... */
6535 read_met_pbl(ctl, met);
6536
6537 /* Calculate tropopause data... */
6538 read_met_tropo(ctl, clim, met);
6539
6540 /* Calculate cloud properties... */
6541 read_met_cloud(met);
6542
6543 /* Calculate convective available potential energy... */
6544 read_met_cape(ctl, clim, met);
6545
6546 /* Calculate total column ozone... */
6547 read_met_ozone(met);
6548
6549 /* Detrending... */
6550 read_met_detrend(ctl, met);
6551
6552 /* Check meteo data and smooth zeta profiles ... */
6553 read_met_monotonize(ctl, met);
6554 }
6555 }
6556
6557 /* Broadcast data via MPI... */
6558#ifdef MPI
6559 if (ctl->met_mpi_share) {
6560
6561 /* Set timer... */
6562 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM");
6563 LOG(2, "Broadcast data on rank %d...", rank);
6564
6565 /* Broadcast... */
6566 broadcast_large_data(met, sizeof(met_t));
6567 }
6568#endif
6569
6570 /* Return success... */
6571 return 1;
6572}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:8184
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:8144
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:10556
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:7983
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:10164
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:8040
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:9810
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:10301
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:9895
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:10527
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:10421
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:7585
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:10362
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:7868
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 6576 of file mptrac.c.

6584 {
6585
6586 /* Initialize modules... */
6587 if (t == ctl->t_start) {
6588
6589 /* Initialize isosurface data... */
6590 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6591 module_isosurf_init(ctl, cache, *met0, *met1, atm);
6592
6593 /* Initialize advection... */
6594 module_advect_init(ctl, cache, *met0, *met1, atm);
6595
6596 /* Initialize chemistry... */
6597 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
6598 }
6599
6600 /* Set time steps of air parcels... */
6601 module_timesteps(ctl, cache, *met0, atm, t);
6602
6603 /* Sort particles... */
6604 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
6605 module_sort(ctl, *met0, atm);
6606
6607
6608 /* Check positions (initial)... */
6609 module_position(cache, *met0, *met1, atm);
6610
6611 /* Advection... */
6612 if (ctl->advect > 0)
6613 module_advect(ctl, cache, *met0, *met1, atm);
6614
6615 /* Turbulent diffusion... */
6616 if (ctl->diffusion == 1
6617 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
6618 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
6619 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
6620 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
6621
6622 /* Mesoscale diffusion... */
6623 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
6624 module_diff_meso(ctl, cache, *met0, *met1, atm);
6625
6626 /* Diffusion... */
6627 if (ctl->diffusion == 2)
6628 module_diff_pbl(ctl, cache, *met0, *met1, atm);
6629
6630 /* Convection... */
6631 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
6632 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
6633 module_convection(ctl, cache, *met0, *met1, atm);
6634
6635 /* Sedimentation... */
6636 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
6637 module_sedi(ctl, cache, *met0, *met1, atm);
6638
6639 /* Isosurface... */
6640 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6641 module_isosurf(ctl, cache, *met0, *met1, atm);
6642
6643 /* Check positions (final)... */
6644 module_position(cache, *met0, *met1, atm);
6645
6646 /* Interpolate meteo data... */
6647 if (ctl->met_dt_out > 0
6648 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
6649 module_meteo(ctl, cache, clim, *met0, *met1, atm);
6650
6651 /* Check boundary conditions (initial)... */
6652 if ((ctl->bound_lat0 < ctl->bound_lat1)
6653 && (ctl->bound_p0 > ctl->bound_p1))
6654 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6655
6656 /* Initialize quantity of total loss rate... */
6657 if (ctl->qnt_loss_rate >= 0) {
6658 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
6659 atm->q[ctl->qnt_loss_rate][ip] = 0;
6660 }
6661 }
6662
6663 /* Decay of particle mass... */
6664 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
6665 module_decay(ctl, cache, clim, atm);
6666
6667 /* Interparcel mixing... */
6668 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
6669 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
6670 module_mixing(ctl, clim, atm, t);
6671
6672 /* Calculate the tracer vmr in the chemistry grid... */
6673 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
6674 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
6675 module_chem_grid(ctl, *met0, *met1, atm, t);
6676
6677 /* OH chemistry... */
6678 if (ctl->oh_chem_reaction != 0)
6679 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
6680
6681 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
6682 if (ctl->h2o2_chem_reaction != 0)
6683 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
6684
6685 /* First-order tracer chemistry... */
6686 if (ctl->tracer_chem)
6687 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
6688
6689 /* Radioactive decay... */
6690 if (ctl->radio_decay)
6691 module_radio_decay(ctl, cache, atm);
6692
6693 /* Domain decomposition... */
6694 if (dd->init) {
6695#ifdef DD
6696 module_dd(ctl, atm, cache, dd, met0);
6697#else
6698 ERRMSG("DD initialized, but model is compiled without DD.")
6699#endif
6700 }
6701
6702 /* KPP chemistry... */
6703 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
6704#ifdef KPP
6705 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
6706#else
6707 ERRMSG("Code was compiled without KPP!");
6708#endif
6709 }
6710
6711 /* Wet deposition... */
6712 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
6713 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
6714 module_wet_depo(ctl, cache, *met0, *met1, atm);
6715
6716 /* Dry deposition... */
6717 if (ctl->dry_depo_vdep > 0)
6718 module_dry_depo(ctl, cache, *met0, *met1, atm);
6719
6720 /* Check boundary conditions (final)... */
6721 if ((ctl->bound_lat0 < ctl->bound_lat1)
6722 && (ctl->bound_p0 > ctl->bound_p1))
6723 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6724}
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:2960
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:4919
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:4177
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:3563
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:3408
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:4284
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:4001
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:5068
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:3246
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:4787
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:3450
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:3150
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:3123
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:4593
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:4542
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:3602
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:4816
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:3804
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:4997
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:3919
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:3679
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:4071
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:4458
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:3856
void module_dd(ctl_t *ctl, atm_t *atm, cache_t *cache, dd_t *dd, met_t **met)
Manages domain decomposition and particle communication in parallel processing.
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 init
Shows if domain decomposition was initialized.
Definition: mptrac.h:3672
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 6728 of file mptrac.c.

6734 {
6735
6736 /* Update GPU... */
6737 if (ctl != NULL) {
6738#ifdef _OPENACC
6739 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6740#pragma acc update device(ctl[:1])
6741#endif
6742 }
6743
6744 if (cache != NULL) {
6745#ifdef _OPENACC
6746 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6747#pragma acc update device(cache[:1])
6748#endif
6749 }
6750
6751 if (clim != NULL) {
6752#ifdef _OPENACC
6753 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6754#pragma acc update device(clim[:1])
6755#endif
6756 }
6757
6758 if (met0 != NULL) {
6759#ifdef _OPENACC
6760 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6761 met_t *met0up = *met0;
6762#pragma acc update device(met0up[:1])
6763#endif
6764 }
6765
6766 if (met1 != NULL) {
6767#ifdef _OPENACC
6768 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6769 met_t *met1up = *met1;
6770#pragma acc update device(met1up[:1])
6771#endif
6772 }
6773
6774 if (atm != NULL) {
6775#ifdef _OPENACC
6776 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6777#pragma acc update device(atm[:1])
6778#endif
6779 }
6780}

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

6790 {
6791
6792 /* Update GPU... */
6793 if (ctl != NULL) {
6794#ifdef _OPENACC
6795 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6796#pragma acc update host(ctl[:1])
6797#endif
6798 }
6799
6800 if (cache != NULL) {
6801#ifdef _OPENACC
6802 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6803#pragma acc update host(cache[:1])
6804#endif
6805 }
6806
6807 if (clim != NULL) {
6808#ifdef _OPENACC
6809 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6810#pragma acc update host(clim[:1])
6811#endif
6812 }
6813
6814 if (met0 != NULL) {
6815#ifdef _OPENACC
6816 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6817 met_t *met0up = *met0;
6818#pragma acc update host(met0up[:1])
6819#endif
6820 }
6821
6822 if (met1 != NULL) {
6823#ifdef _OPENACC
6824 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6825 met_t *met1up = *met1;
6826#pragma acc update host(met1up[:1])
6827#endif
6828 }
6829
6830 if (atm != NULL) {
6831#ifdef _OPENACC
6832 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6833#pragma acc update host(atm[:1])
6834#endif
6835 }
6836}

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

6844 {
6845
6846 /* Set timer... */
6847 SELECT_TIMER("WRITE_ATM", "OUTPUT");
6848
6849 /* Write info... */
6850 LOG(1, "Write atmospheric data: %s", filename);
6851
6852 /* Write ASCII data... */
6853 if (ctl->atm_type_out == 0)
6854 write_atm_asc(filename, ctl, atm, t);
6855
6856 /* Write binary data... */
6857 else if (ctl->atm_type_out == 1)
6858 write_atm_bin(filename, ctl, atm);
6859
6860 /* Write netCDF data... */
6861 else if (ctl->atm_type_out == 2)
6862 write_atm_nc(filename, ctl, atm);
6863
6864 /* Write CLaMS trajectory data... */
6865 else if (ctl->atm_type_out == 3)
6866 write_atm_clams_traj(filename, ctl, atm, t);
6867
6868 /* Write CLaMS pos data... */
6869 else if (ctl->atm_type_out == 4)
6870 write_atm_clams(filename, ctl, atm);
6871
6872 /* Error... */
6873 else
6874 ERRMSG("Atmospheric data type not supported!");
6875
6876 /* Write info... */
6877 double mini, maxi;
6878 LOG(2, "Number of particles: %d", atm->np);
6879 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6880 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6881 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6882 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6883 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6884 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6885 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
6886 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6887 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
6888 for (int iq = 0; iq < ctl->nq; iq++) {
6889 char msg[5 * LEN];
6890 sprintf(msg, "Quantity %s range: %s ... %s %s",
6891 ctl->qnt_name[iq], ctl->qnt_format[iq],
6892 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6893 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6894 LOG(2, msg, mini, maxi);
6895 }
6896}
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:11517
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:11332
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:11464
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:11414
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:11675
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 6900 of file mptrac.c.

6903 {
6904
6905 /* Set timer... */
6906 SELECT_TIMER("WRITE_MET", "OUTPUT");
6907
6908 /* Write info... */
6909 LOG(1, "Write meteo data: %s", filename);
6910
6911 /* Check compression flags... */
6912#ifndef ZFP
6913 if (ctl->met_type == 3)
6914 ERRMSG("MPTRAC was compiled without ZFP compression!");
6915#endif
6916#ifndef ZSTD
6917 if (ctl->met_type == 4)
6918 ERRMSG("MPTRAC was compiled without ZSTD compression!");
6919#endif
6920#ifndef CMS
6921 if (ctl->met_type == 5)
6922 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6923#endif
6924#ifndef SZ3
6925 if (ctl->met_type == 7)
6926 ERRMSG("MPTRAC was compiled without SZ3 compression!");
6927#endif
6928
6929 /* Write netCDF data... */
6930 if (ctl->met_type == 0)
6931 write_met_nc(filename, ctl, met);
6932
6933 /* Write binary data... */
6934 else if (ctl->met_type >= 1 && ctl->met_type <= 7)
6935 write_met_bin(filename, ctl, met);
6936
6937 /* Not implemented... */
6938 else
6939 ERRMSG("MET_TYPE not implemented!");
6940}
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:12752
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:12521
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 6944 of file mptrac.c.

6950 {
6951
6952 char ext[10], filename[2 * LEN];
6953
6954 double r;
6955
6956 int year, mon, day, hour, min, sec;
6957
6958 /* Get time... */
6959 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
6960
6961 /* Update host... */
6962 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
6963 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
6964 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
6965 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
6966 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
6967 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
6968 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
6969
6970 /* Write atmospheric data... */
6971 if (ctl->atm_basename[0] != '-' &&
6972 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
6973 if (ctl->atm_type_out == 0)
6974 sprintf(ext, "tab");
6975 else if (ctl->atm_type_out == 1)
6976 sprintf(ext, "bin");
6977 else if (ctl->atm_type_out == 2)
6978 sprintf(ext, "nc");
6979 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6980 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
6981 mptrac_write_atm(filename, ctl, atm, t);
6982 }
6983
6984 /* Write gridded data... */
6985 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
6986 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6987 dirname, ctl->grid_basename, year, mon, day, hour, min,
6988 ctl->grid_type == 0 ? "tab" : "nc");
6989 write_grid(filename, ctl, met0, met1, atm, t);
6990 }
6991
6992 /* Write CSI data... */
6993 if (ctl->csi_basename[0] != '-') {
6994 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
6995 write_csi(filename, ctl, atm, t);
6996 }
6997
6998 /* Write ensemble data... */
6999 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
7000 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
7001 dirname, ctl->ens_basename, year, mon, day, hour, min);
7002 write_ens(filename, ctl, atm, t);
7003 }
7004
7005 /* Write profile data... */
7006 if (ctl->prof_basename[0] != '-') {
7007 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
7008 write_prof(filename, ctl, met0, met1, atm, t);
7009 }
7010
7011 /* Write sample data... */
7012 if (ctl->sample_basename[0] != '-') {
7013 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
7014 write_sample(filename, ctl, met0, met1, atm, t);
7015 }
7016
7017 /* Write station data... */
7018 if (ctl->stat_basename[0] != '-') {
7019 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
7020 write_station(filename, ctl, atm, t);
7021 }
7022
7023 /* Write VTK data... */
7024 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
7025 static int nvtk;
7026 if (t == ctl->t_start)
7027 nvtk = 0;
7028 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
7029 write_vtk(filename, ctl, atm, t);
7030 }
7031}
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:6840
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:11999
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:12975
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:6784
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:13364
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:13450
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:13202
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:12096
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:11724
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 7035 of file mptrac.c.

7038 {
7039
7040 /* Check water vapor volume mixing ratio... */
7041 const double h2o_help = MAX(h2o, 0.1e-6);
7042
7043 /* Calculate T_NAT... */
7044 const double p_hno3 = hno3 * p / 1.333224;
7045 const double p_h2o = h2o_help * p / 1.333224;
7046 const double a = 0.009179 - 0.00088 * log10(p_h2o);
7047 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
7048 const double c = -11397.0 / a;
7049 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
7050 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
7051 if (x2 > 0)
7052 tnat = x2;
7053
7054 return tnat;
7055}

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

7064 {
7065
7066 /* Get pressure range... */
7067 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
7068 const double p0 = pbl;
7069
7070 /* Get weighting factor... */
7071 if (atm->p[ip] > p0)
7072 return 1;
7073 else if (atm->p[ip] < p1)
7074 return 0;
7075 else
7076 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
7077}

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

7084 {
7085
7086 /* Open file... */
7087 FILE *in;
7088 if (!(in = fopen(filename, "r"))) {
7089 WARN("Cannot open file!");
7090 return 0;
7091 }
7092
7093 /* Read line... */
7094 char line[LEN];
7095 while (fgets(line, LEN, in)) {
7096
7097 /* Read data... */
7098 char *tok;
7099 TOK(line, tok, "%lg", atm->time[atm->np]);
7100 TOK(NULL, tok, "%lg", atm->p[atm->np]);
7101 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
7102 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
7103 for (int iq = 0; iq < ctl->nq; iq++)
7104 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
7105
7106 /* Convert altitude to pressure... */
7107 atm->p[atm->np] = P(atm->p[atm->np]);
7108
7109 /* Increment data point counter... */
7110 if ((++atm->np) > NP)
7111 ERRMSG("Too many data points!");
7112 }
7113
7114 /* Close file... */
7115 fclose(in);
7116
7117 /* Return success... */
7118 return 1;
7119}
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1833

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

7126 {
7127
7128 /* Open file... */
7129 FILE *in;
7130 if (!(in = fopen(filename, "r")))
7131 return 0;
7132
7133 /* Check version of binary data... */
7134 int version;
7135 FREAD(&version, int,
7136 1,
7137 in);
7138 if (version != 100)
7139 ERRMSG("Wrong version of binary data!");
7140
7141 /* Read data... */
7142 FREAD(&atm->np, int,
7143 1,
7144 in);
7145 FREAD(atm->time, double,
7146 (size_t) atm->np,
7147 in);
7148 FREAD(atm->p, double,
7149 (size_t) atm->np,
7150 in);
7151 FREAD(atm->lon, double,
7152 (size_t) atm->np,
7153 in);
7154 FREAD(atm->lat, double,
7155 (size_t) atm->np,
7156 in);
7157 for (int iq = 0; iq < ctl->nq; iq++)
7158 FREAD(atm->q[iq], double,
7159 (size_t) atm->np,
7160 in);
7161
7162 /* Read final flag... */
7163 int final;
7164 FREAD(&final, int,
7165 1,
7166 in);
7167 if (final != 999)
7168 ERRMSG("Error while reading binary data!");
7169
7170 /* Close file... */
7171 fclose(in);
7172
7173 /* Return success... */
7174 return 1;
7175}

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

7182 {
7183
7184 int ncid, varid;
7185
7186 /* Open file... */
7187 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7188 return 0;
7189
7190 /* Get dimensions... */
7191 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
7192
7193 /* Get time... */
7194 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
7195 NC(nc_get_var_double(ncid, varid, atm->time));
7196 } else {
7197 WARN("TIME_INIT not found use time instead!");
7198 double time_init;
7199 NC_GET_DOUBLE("time", &time_init, 1);
7200 for (int ip = 0; ip < atm->np; ip++) {
7201 atm->time[ip] = time_init;
7202 }
7203 }
7204
7205 /* Read zeta coordinate, pressure is optional... */
7206 if (ctl->advect_vert_coord == 1) {
7207 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
7208 NC_GET_DOUBLE("PRESS", atm->p, 0);
7209 }
7210
7211 /* Read pressure, zeta coordinate is optional... */
7212 else {
7213 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
7214 NC(nc_get_var_double(ncid, varid, atm->p));
7215 } else {
7216 WARN("PRESS_INIT not found use PRESS instead!");
7217 nc_inq_varid(ncid, "PRESS", &varid);
7218 NC(nc_get_var_double(ncid, varid, atm->p));
7219 }
7220 }
7221
7222 /* Read further quantities if requested... */
7223 for (int iq = 0; iq < ctl->nq; iq++)
7224 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7225
7226 /* Read longitude and latitude... */
7227 NC_GET_DOUBLE("LON", atm->lon, 1);
7228 NC_GET_DOUBLE("LAT", atm->lat, 1);
7229
7230 /* Close file... */
7231 NC(nc_close(ncid));
7232
7233 /* Return success... */
7234 return 1;
7235}
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1167
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1226
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1256

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

7242 {
7243
7244 int ncid, varid;
7245
7246 /* Open file... */
7247 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7248 return 0;
7249
7250 /* Get dimensions... */
7251 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
7252
7253 /* Read geolocations... */
7254 NC_GET_DOUBLE("time", atm->time, 1);
7255 NC_GET_DOUBLE("press", atm->p, 1);
7256 NC_GET_DOUBLE("lon", atm->lon, 1);
7257 NC_GET_DOUBLE("lat", atm->lat, 1);
7258
7259 /* Read variables... */
7260 for (int iq = 0; iq < ctl->nq; iq++)
7261 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7262
7263 /* Close file... */
7264 NC(nc_close(ncid));
7265
7266 /* Return success... */
7267 return 1;
7268}

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

7274 {
7275
7276 int ncid, varid;
7277
7278 /* Write info... */
7279 LOG(1, "Read photolysis rates: %s", filename);
7280
7281 /* Open netCDF file... */
7282 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7283 WARN("Photolysis rate data are missing!");
7284 return;
7285 }
7286
7287 /* Read pressure data... */
7288 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
7289 NC_GET_DOUBLE("press", photo->p, 1);
7290 if (photo->p[0] < photo->p[1])
7291 ERRMSG("Pressure data are not descending!");
7292
7293 /* Read total column ozone data... */
7294 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
7295 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
7296 if (photo->o3c[0] > photo->o3c[1])
7297 ERRMSG("Total column ozone data are not ascending!");
7298
7299 /* Read solar zenith angle data... */
7300 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
7301 NC_GET_DOUBLE("sza", photo->sza, 1);
7302 if (photo->sza[0] > photo->sza[1])
7303 ERRMSG("Solar zenith angle data are not ascending!");
7304
7305 /* Read data... */
7306 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
7307 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
7308 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
7309 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
7310 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
7311 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
7312 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
7313 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
7314 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
7315
7316 /* Close netCDF file... */
7317 NC(nc_close(ncid));
7318
7319 /* Write info... */
7320 LOG(2, "Number of pressure levels: %d", photo->np);
7321 LOG(2, "Altitude levels: %g, %g ... %g km",
7322 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
7323 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7324 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
7325 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
7326 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
7327 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
7328 RAD2DEG(photo->sza[photo->nsza - 1]));
7329 LOG(2, "Number of total column ozone values: %d", photo->no3c);
7330 LOG(2, "Total column ozone: %g, %g ... %g DU",
7331 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
7332 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
7333 photo->n2o[0][0][0], photo->n2o[1][0][0],
7334 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7335 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
7336 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
7337 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7338 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
7339 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
7340 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7341 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
7342 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
7343 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7344 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
7345 photo->o2[0][0][0], photo->o2[1][0][0],
7346 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7347 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
7348 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
7349 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7350 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
7351 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
7352 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7353 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
7354 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
7355 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7356 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
7357 photo->h2o[0][0][0], photo->h2o[1][0][0],
7358 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7359}
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:7363
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:348
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:343
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:353
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3308
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3305
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3314
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3317
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3311
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 7363 of file mptrac.c.

7367 {
7368
7369 /* Allocate... */
7370 double *help;
7371 ALLOC(help, double,
7372 photo->np * photo->nsza * photo->no3c);
7373
7374 /* Read varible... */
7375 int varid;
7376 NC_GET_DOUBLE(varname, help, 1);
7377
7378 /* Copy data... */
7379 for (int ip = 0; ip < photo->np; ip++)
7380 for (int is = 0; is < photo->nsza; is++)
7381 for (int io = 0; io < photo->no3c; io++)
7382 var[ip][is][io] =
7383 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
7384
7385 /* Free... */
7386 free(help);
7387}

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

7393 {
7394
7395 /* Write info... */
7396 LOG(1, "Read climatological time series: %s", filename);
7397
7398 /* Open file... */
7399 FILE *in;
7400 if (!(in = fopen(filename, "r"))) {
7401 WARN("Cannot open file!");
7402 return 0;
7403 }
7404
7405 /* Read data... */
7406 char line[LEN];
7407 int nh = 0;
7408 while (fgets(line, LEN, in))
7409 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
7410
7411 /* Convert years to seconds... */
7412 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
7413
7414 /* Check data... */
7415 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
7416 ERRMSG("Time series must be ascending!");
7417
7418 /* Count time steps... */
7419 if ((++nh) >= CTS)
7420 ERRMSG("Too many data points!");
7421 }
7422
7423 /* Close file... */
7424 fclose(in);
7425
7426 /* Check number of data points... */
7427 ts->ntime = nh;
7428 if (nh < 2)
7429 ERRMSG("Not enough data points!");
7430
7431 /* Write info... */
7432 LOG(2, "Number of time steps: %d", ts->ntime);
7433 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
7434 ts->time[nh - 1]);
7435 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
7436 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
7437 (size_t) nh));
7438
7439 /* Exit success... */
7440 return 1;
7441}
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:363

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

7448 {
7449
7450 int ncid, varid, it, iy, iz, iz2, nt;
7451
7452 double *help, varmin = 1e99, varmax = -1e99;
7453
7454 /* Write info... */
7455 LOG(1, "Read %s data: %s", varname, filename);
7456
7457 /* Open netCDF file... */
7458 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7459 WARN("%s climatology data are missing!", varname);
7460 return;
7461 }
7462
7463 /* Read pressure data... */
7464 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
7465 NC_GET_DOUBLE("press", zm->p, 1);
7466 if (zm->p[0] < zm->p[1])
7467 ERRMSG("Pressure data are not descending!");
7468
7469 /* Read latitudes... */
7470 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
7471 NC_GET_DOUBLE("lat", zm->lat, 1);
7472 if (zm->lat[0] > zm->lat[1])
7473 ERRMSG("Latitude data are not ascending!");
7474
7475 /* Set time data (for monthly means)... */
7476 zm->ntime = 12;
7477 zm->time[0] = 1209600.00;
7478 zm->time[1] = 3888000.00;
7479 zm->time[2] = 6393600.00;
7480 zm->time[3] = 9072000.00;
7481 zm->time[4] = 11664000.00;
7482 zm->time[5] = 14342400.00;
7483 zm->time[6] = 16934400.00;
7484 zm->time[7] = 19612800.00;
7485 zm->time[8] = 22291200.00;
7486 zm->time[9] = 24883200.00;
7487 zm->time[10] = 27561600.00;
7488 zm->time[11] = 30153600.00;
7489
7490 /* Check number of timesteps... */
7491 NC_INQ_DIM("time", &nt, 12, 12, 1);
7492
7493 /* Read data... */
7494 ALLOC(help, double,
7495 zm->nlat * zm->np * zm->ntime);
7496 NC_GET_DOUBLE(varname, help, 1);
7497 for (it = 0; it < zm->ntime; it++)
7498 for (iz = 0; iz < zm->np; iz++)
7499 for (iy = 0; iy < zm->nlat; iy++)
7500 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
7501 free(help);
7502
7503 /* Fix data gaps... */
7504 for (it = 0; it < zm->ntime; it++)
7505 for (iy = 0; iy < zm->nlat; iy++)
7506 for (iz = 0; iz < zm->np; iz++) {
7507 if (zm->vmr[it][iz][iy] < 0) {
7508 for (iz2 = 0; iz2 < zm->np; iz2++)
7509 if (zm->vmr[it][iz2][iy] >= 0) {
7510 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7511 break;
7512 }
7513 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
7514 if (zm->vmr[it][iz2][iy] >= 0) {
7515 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7516 break;
7517 }
7518 }
7519 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
7520 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
7521 }
7522
7523 /* Close netCDF file... */
7524 NC(nc_close(ncid));
7525
7526 /* Write info... */
7527 LOG(2, "Number of time steps: %d", zm->ntime);
7528 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
7529 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
7530 LOG(2, "Number of pressure levels: %d", zm->np);
7531 LOG(2, "Altitude levels: %g, %g ... %g km",
7532 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
7533 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
7534 zm->p[1], zm->p[zm->np - 1]);
7535 LOG(2, "Number of latitudes: %d", zm->nlat);
7536 LOG(2, "Latitudes: %g, %g ... %g deg",
7537 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
7538 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
7539 varmax);
7540}
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:338

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

7548 {
7549
7550 /* Write info... */
7551 LOG(1, "Read kernel function: %s", filename);
7552
7553 /* Open file... */
7554 FILE *in;
7555 if (!(in = fopen(filename, "r")))
7556 ERRMSG("Cannot open file!");
7557
7558 /* Read data... */
7559 char line[LEN];
7560 int n = 0;
7561 while (fgets(line, LEN, in))
7562 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
7563 if (n > 0 && kz[n] < kz[n - 1])
7564 ERRMSG("Height levels must be ascending!");
7565 if ((++n) >= EP)
7566 ERRMSG("Too many height levels!");
7567 }
7568
7569 /* Close file... */
7570 fclose(in);
7571
7572 /* Check number of data points... */
7573 *nk = n;
7574 if (n < 2)
7575 ERRMSG("Not enough height levels!");
7576
7577 /* Normalize kernel function... */
7578 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
7579 for (int iz = 0; iz < n; iz++)
7580 kw[iz] /= kmax;
7581}

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

7588 {
7589
7590 FILE *in;
7591
7592 double r;
7593
7594 int year, mon, day, hour, min, sec;
7595
7596 /* Set timer... */
7597 SELECT_TIMER("READ_MET_BIN", "INPUT");
7598
7599 /* Open file... */
7600 if (!(in = fopen(filename, "r"))) {
7601 WARN("Cannot open file!");
7602 return 0;
7603 }
7604
7605 /* Check type of binary data... */
7606 int met_type;
7607 FREAD(&met_type, int,
7608 1,
7609 in);
7610 if (met_type != ctl->met_type)
7611 ERRMSG("Wrong MET_TYPE of binary data!");
7612
7613 /* Check version of binary data... */
7614 int version;
7615 FREAD(&version, int,
7616 1,
7617 in);
7618 if (version != 103)
7619 ERRMSG("Wrong version of binary data!");
7620
7621 /* Read time... */
7622 FREAD(&met->time, double,
7623 1,
7624 in);
7625 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7626 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7627 met->time, year, mon, day, hour, min);
7628 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7629 || day < 1 || day > 31 || hour < 0 || hour > 23)
7630 ERRMSG("Error while reading time!");
7631
7632 /* Read dimensions... */
7633 FREAD(&met->nx, int,
7634 1,
7635 in);
7636 LOG(2, "Number of longitudes: %d", met->nx);
7637 if (met->nx < 2 || met->nx > EX)
7638 ERRMSG("Number of longitudes out of range!");
7639
7640 FREAD(&met->ny, int,
7641 1,
7642 in);
7643 LOG(2, "Number of latitudes: %d", met->ny);
7644 if (met->ny < 2 || met->ny > EY)
7645 ERRMSG("Number of latitudes out of range!");
7646
7647 FREAD(&met->np, int,
7648 1,
7649 in);
7650 LOG(2, "Number of levels: %d", met->np);
7651 if (met->np < 2 || met->np > EP)
7652 ERRMSG("Number of levels out of range!");
7653
7654 /* Read grid... */
7655 FREAD(met->lon, double,
7656 (size_t) met->nx,
7657 in);
7658 LOG(2, "Longitudes: %g, %g ... %g deg",
7659 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7660
7661 FREAD(met->lat, double,
7662 (size_t) met->ny,
7663 in);
7664 LOG(2, "Latitudes: %g, %g ... %g deg",
7665 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7666
7667 FREAD(met->p, double,
7668 (size_t) met->np,
7669 in);
7670 LOG(2, "Altitude levels: %g, %g ... %g km",
7671 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7672 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7673 met->p[0], met->p[1], met->p[met->np - 1]);
7674
7675 /* Read surface data... */
7676 read_met_bin_2d(in, met, met->ps, "PS");
7677 read_met_bin_2d(in, met, met->ts, "TS");
7678 read_met_bin_2d(in, met, met->zs, "ZS");
7679 read_met_bin_2d(in, met, met->us, "US");
7680 read_met_bin_2d(in, met, met->vs, "VS");
7681 read_met_bin_2d(in, met, met->ess, "ESS");
7682 read_met_bin_2d(in, met, met->nss, "NSS");
7683 read_met_bin_2d(in, met, met->shf, "SHF");
7684 read_met_bin_2d(in, met, met->lsm, "LSM");
7685 read_met_bin_2d(in, met, met->sst, "SST");
7686 read_met_bin_2d(in, met, met->pbl, "PBL");
7687 read_met_bin_2d(in, met, met->pt, "PT");
7688 read_met_bin_2d(in, met, met->tt, "TT");
7689 read_met_bin_2d(in, met, met->zt, "ZT");
7690 read_met_bin_2d(in, met, met->h2ot, "H2OT");
7691 read_met_bin_2d(in, met, met->pct, "PCT");
7692 read_met_bin_2d(in, met, met->pcb, "PCB");
7693 read_met_bin_2d(in, met, met->cl, "CL");
7694 read_met_bin_2d(in, met, met->plcl, "PLCL");
7695 read_met_bin_2d(in, met, met->plfc, "PLFC");
7696 read_met_bin_2d(in, met, met->pel, "PEL");
7697 read_met_bin_2d(in, met, met->cape, "CAPE");
7698 read_met_bin_2d(in, met, met->cin, "CIN");
7699 read_met_bin_2d(in, met, met->o3c, "O3C");
7700
7701 /* Read level data... */
7702 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
7703 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
7704 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
7705 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
7706 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
7707 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
7708 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
7709 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
7710 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
7711 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
7712 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
7713 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
7714 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
7715
7716 /* Read final flag... */
7717 int final;
7718 FREAD(&final, int,
7719 1,
7720 in);
7721 if (final != 999)
7722 ERRMSG("Error while reading binary data!");
7723
7724 /* Close file... */
7725 fclose(in);
7726
7727 /* Return success... */
7728 return 1;
7729}
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:7733
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:7762
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:293
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3517
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3505
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3577
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3547
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3541
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3523
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3499
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3574
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3487
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3586
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3481
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3493
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3526
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3538
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3544
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3532
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3514
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3508
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3490
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3502
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3580
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3520
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3565
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3529
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3496
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3535
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3583
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 7733 of file mptrac.c.

7737 {
7738
7739 float *help;
7740
7741 /* Allocate... */
7742 ALLOC(help, float,
7743 EX * EY);
7744
7745 /* Read uncompressed... */
7746 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
7747 FREAD(help, float,
7748 (size_t) (met->nx * met->ny),
7749 in);
7750
7751 /* Copy data... */
7752 for (int ix = 0; ix < met->nx; ix++)
7753 for (int iy = 0; iy < met->ny; iy++)
7754 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
7755
7756 /* Free... */
7757 free(help);
7758}
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:439

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

7769 {
7770
7771 float *help;
7772
7773 /* Allocate... */
7774 ALLOC(help, float,
7775 EX * EY * EP);
7776
7777 /* Read uncompressed data... */
7778 if (ctl->met_type == 1) {
7779 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
7780 FREAD(help, float,
7781 (size_t) (met->nx * met->ny * met->np),
7782 in);
7783 }
7784
7785 /* Read packed data... */
7786 else if (ctl->met_type == 2)
7787 compress_pck(varname, help, (size_t) (met->ny * met->nx),
7788 (size_t) met->np, 1, in);
7789
7790 /* Read ZFP data... */
7791 else if (ctl->met_type == 3) {
7792#ifdef ZFP
7793 int precision;
7794 FREAD(&precision, int,
7795 1,
7796 in);
7797
7798 double tolerance;
7799 FREAD(&tolerance, double,
7800 1,
7801 in);
7802
7803 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
7804 tolerance, 1, in);
7805#else
7806 ERRMSG("MPTRAC was compiled without ZFP compression!");
7807#endif
7808 }
7809
7810 /* Read zstd data... */
7811 else if (ctl->met_type == 4) {
7812#ifdef ZSTD
7813 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
7814 ctl->met_zstd_level, in);
7815#else
7816 ERRMSG("MPTRAC was compiled without ZSTD compression!");
7817#endif
7818 }
7819
7820 /* Read cmultiscale data... */
7821 else if (ctl->met_type == 5) {
7822#ifdef CMS
7823 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
7824 (size_t) met->np, met->p, 1, in);
7825#else
7826 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
7827#endif
7828 }
7829
7830 /* Read SZ3 data... */
7831 else if (ctl->met_type == 7) {
7832#ifdef SZ3
7833 int precision;
7834 FREAD(&precision, int,
7835 1,
7836 in);
7837
7838 double tolerance;
7839 FREAD(&tolerance, double,
7840 1,
7841 in);
7842
7843 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
7844 tolerance, 1, in);
7845#else
7846 ERRMSG("MPTRAC was compiled without sz3 compression!");
7847#endif
7848 }
7849
7850 /* Copy data... */
7851#pragma omp parallel for default(shared) collapse(2)
7852 for (int ix = 0; ix < met->nx; ix++)
7853 for (int iy = 0; iy < met->ny; iy++)
7854 for (int ip = 0; ip < met->np; ip++) {
7855 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7856 if (var[ix][iy][ip] < bound_min)
7857 var[ix][iy][ip] = bound_min;
7858 else if (var[ix][iy][ip] > bound_max)
7859 var[ix][iy][ip] = bound_max;
7860 }
7861
7862 /* Free... */
7863 free(help);
7864}
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:2504
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 7868 of file mptrac.c.

7871 {
7872
7873 /* Check parameters... */
7874 if (ctl->met_cape != 1)
7875 return;
7876
7877 /* Set timer... */
7878 SELECT_TIMER("READ_MET_CAPE", "METPROC");
7879 LOG(2, "Calculate CAPE...");
7880
7881 /* Vertical spacing (about 100 m)... */
7882 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
7883
7884 /* Loop over columns... */
7885#pragma omp parallel for default(shared) collapse(2)
7886 for (int ix = 0; ix < met->nx; ix++)
7887 for (int iy = 0; iy < met->ny; iy++) {
7888
7889 /* Get potential temperature and water vapor at lowest 50 hPa... */
7890 int n = 0;
7891 double h2o = 0, t, theta = 0;
7892 double pbot = MIN(met->ps[ix][iy], met->p[0]);
7893 double ptop = pbot - 50.;
7894 for (int ip = 0; ip < met->np; ip++) {
7895 if (met->p[ip] <= pbot) {
7896 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
7897 h2o += met->h2o[ix][iy][ip];
7898 n++;
7899 }
7900 if (met->p[ip] < ptop && n > 0)
7901 break;
7902 }
7903 theta /= n;
7904 h2o /= n;
7905
7906 /* Cannot compute anything if water vapor is missing... */
7907 met->plcl[ix][iy] = NAN;
7908 met->plfc[ix][iy] = NAN;
7909 met->pel[ix][iy] = NAN;
7910 met->cape[ix][iy] = NAN;
7911 met->cin[ix][iy] = NAN;
7912 if (h2o <= 0)
7913 continue;
7914
7915 /* Find lifted condensation level (LCL)... */
7916 ptop = P(20.);
7917 pbot = met->ps[ix][iy];
7918 do {
7919 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
7920 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
7921 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
7922 ptop = met->plcl[ix][iy];
7923 else
7924 pbot = met->plcl[ix][iy];
7925 } while (pbot - ptop > 0.1);
7926
7927 /* Calculate CIN up to LCL... */
7929 double dcape, dz, h2o_env, t_env;
7930 double p = met->ps[ix][iy];
7931 met->cape[ix][iy] = met->cin[ix][iy] = 0;
7932 do {
7933 dz = dz0 * TVIRT(t, h2o);
7934 p /= pfac;
7935 t = theta / pow(1000. / p, 0.286);
7936 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7937 &t_env, ci, cw, 1);
7938 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7939 &h2o_env, ci, cw, 0);
7940 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7941 TVIRT(t_env, h2o_env) * dz;
7942 if (dcape < 0)
7943 met->cin[ix][iy] += fabsf((float) dcape);
7944 } while (p > met->plcl[ix][iy]);
7945
7946 /* Calculate level of free convection (LFC), equilibrium level (EL),
7947 and convective available potential energy (CAPE)... */
7948 dcape = 0;
7949 p = met->plcl[ix][iy];
7950 t = theta / pow(1000. / p, 0.286);
7951 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
7952 do {
7953 dz = dz0 * TVIRT(t, h2o);
7954 p /= pfac;
7955 t -= lapse_rate(t, h2o) * dz;
7956 double psat = PSAT(t);
7957 h2o = psat / (p - (1. - EPS) * psat);
7958 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7959 &t_env, ci, cw, 1);
7960 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7961 &h2o_env, ci, cw, 0);
7962 double dcape_old = dcape;
7963 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7964 TVIRT(t_env, h2o_env) * dz;
7965 if (dcape > 0) {
7966 met->cape[ix][iy] += (float) dcape;
7967 if (!isfinite(met->plfc[ix][iy]))
7968 met->plfc[ix][iy] = (float) p;
7969 } else if (dcape_old > 0)
7970 met->pel[ix][iy] = (float) p;
7971 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
7972 met->cin[ix][iy] += fabsf((float) dcape);
7973 } while (p > ptop);
7974
7975 /* Check results... */
7976 if (!isfinite(met->plfc[ix][iy]))
7977 met->cin[ix][iy] = NAN;
7978 }
7979}
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 7983 of file mptrac.c.

7984 {
7985
7986 /* Set timer... */
7987 SELECT_TIMER("READ_MET_CLOUD", "METPROC");
7988 LOG(2, "Calculate cloud data...");
7989
7990 /* Thresholds for cloud detection... */
7991 const double ccmin = 0.01, cwmin = 1e-6;
7992
7993 /* Loop over columns... */
7994#pragma omp parallel for default(shared) collapse(2)
7995 for (int ix = 0; ix < met->nx; ix++)
7996 for (int iy = 0; iy < met->ny; iy++) {
7997
7998 /* Init... */
7999 met->pct[ix][iy] = NAN;
8000 met->pcb[ix][iy] = NAN;
8001 met->cl[ix][iy] = 0;
8002
8003 /* Loop over pressure levels... */
8004 for (int ip = 0; ip < met->np - 1; ip++) {
8005
8006 /* Check pressure... */
8007 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
8008 continue;
8009
8010 /* Check ice water and liquid water content... */
8011 if (met->cc[ix][iy][ip] > ccmin
8012 && (met->lwc[ix][iy][ip] > cwmin
8013 || met->rwc[ix][iy][ip] > cwmin
8014 || met->iwc[ix][iy][ip] > cwmin
8015 || met->swc[ix][iy][ip] > cwmin)) {
8016
8017 /* Get cloud top pressure ... */
8018 met->pct[ix][iy]
8019 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
8020
8021 /* Get cloud bottom pressure ... */
8022 if (!isfinite(met->pcb[ix][iy]))
8023 met->pcb[ix][iy]
8024 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
8025 }
8026
8027 /* Get cloud water... */
8028 met->cl[ix][iy] += (float)
8029 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
8030 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
8031 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
8032 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
8033 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
8034 }
8035 }
8036}

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

8042 {
8043
8044 met_t *help;
8045
8046 /* Check parameters... */
8047 if (ctl->met_detrend <= 0)
8048 return;
8049
8050 /* Set timer... */
8051 SELECT_TIMER("READ_MET_DETREND", "METPROC");
8052 LOG(2, "Detrend meteo data...");
8053
8054 /* Allocate... */
8055 ALLOC(help, met_t, 1);
8056
8057 /* Calculate standard deviation... */
8058 const double sigma = ctl->met_detrend / 2.355;
8059 const double tssq = 2. * SQR(sigma);
8060
8061 /* Calculate box size in latitude... */
8062 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
8063 sy = MIN(MAX(1, sy), met->ny / 2);
8064
8065 /* Calculate background... */
8066#pragma omp parallel for default(shared) collapse(2)
8067 for (int ix = 0; ix < met->nx; ix++) {
8068 for (int iy = 0; iy < met->ny; iy++) {
8069
8070 /* Calculate Cartesian coordinates... */
8071 double x0[3];
8072 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
8073
8074 /* Calculate box size in longitude... */
8075 int sx =
8076 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
8077 fabs(met->lon[1] - met->lon[0]));
8078 sx = MIN(MAX(1, sx), met->nx / 2);
8079
8080 /* Init... */
8081 float wsum = 0;
8082 for (int ip = 0; ip < met->np; ip++) {
8083 help->t[ix][iy][ip] = 0;
8084 help->u[ix][iy][ip] = 0;
8085 help->v[ix][iy][ip] = 0;
8086 help->w[ix][iy][ip] = 0;
8087 }
8088
8089 /* Loop over neighboring grid points... */
8090 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
8091 int ix3 = ix2;
8092 if (ix3 < 0)
8093 ix3 += met->nx;
8094 else if (ix3 >= met->nx)
8095 ix3 -= met->nx;
8096 for (int iy2 = MAX(iy - sy, 0);
8097 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
8098
8099 /* Calculate Cartesian coordinates... */
8100 double x1[3];
8101 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
8102
8103 /* Calculate weighting factor... */
8104 const float w = (float) exp(-DIST2(x0, x1) / tssq);
8105
8106 /* Add data... */
8107 wsum += w;
8108 for (int ip = 0; ip < met->np; ip++) {
8109 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
8110 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
8111 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
8112 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
8113 }
8114 }
8115 }
8116
8117 /* Normalize... */
8118 for (int ip = 0; ip < met->np; ip++) {
8119 help->t[ix][iy][ip] /= wsum;
8120 help->u[ix][iy][ip] /= wsum;
8121 help->v[ix][iy][ip] /= wsum;
8122 help->w[ix][iy][ip] /= wsum;
8123 }
8124 }
8125 }
8126
8127 /* Subtract background... */
8128#pragma omp parallel for default(shared) collapse(3)
8129 for (int ix = 0; ix < met->nx; ix++)
8130 for (int iy = 0; iy < met->ny; iy++)
8131 for (int ip = 0; ip < met->np; ip++) {
8132 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
8133 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
8134 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
8135 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
8136 }
8137
8138 /* Free... */
8139 free(help);
8140}
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:1950
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:683
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 8144 of file mptrac.c.

8145 {
8146
8147 /* Set timer... */
8148 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC");
8149 LOG(2, "Extrapolate meteo data...");
8150
8151 /* Loop over columns... */
8152#pragma omp parallel for default(shared) collapse(2)
8153 for (int ix = 0; ix < met->nx; ix++)
8154 for (int iy = 0; iy < met->ny; iy++) {
8155
8156 /* Find lowest valid data point... */
8157 int ip0;
8158 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
8159 if (!isfinite(met->t[ix][iy][ip0])
8160 || !isfinite(met->u[ix][iy][ip0])
8161 || !isfinite(met->v[ix][iy][ip0])
8162 || !isfinite(met->w[ix][iy][ip0]))
8163 break;
8164
8165 /* Extrapolate... */
8166 for (int ip = ip0; ip >= 0; ip--) {
8167 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
8168 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
8169 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
8170 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
8171 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
8172 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
8173 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
8174 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
8175 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
8176 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
8177 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
8178 }
8179 }
8180}

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

8186 {
8187
8188 float *help;
8189
8190 double logp[EP];
8191
8192 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
8193
8194 /* Set timer... */
8195 SELECT_TIMER("READ_MET_GEOPOT", "METPROC");
8196 LOG(2, "Calculate geopotential heights...");
8197
8198 /* Allocate... */
8199 ALLOC(help, float,
8200 EX * EY * EP);
8201
8202 /* Calculate log pressure... */
8203#pragma omp parallel for default(shared)
8204 for (int ip = 0; ip < met->np; ip++)
8205 logp[ip] = log(met->p[ip]);
8206
8207 /* Apply hydrostatic equation to calculate geopotential heights... */
8208#pragma omp parallel for default(shared) collapse(2)
8209 for (int ix = 0; ix < met->nx; ix++)
8210 for (int iy = 0; iy < met->ny; iy++) {
8211
8212 /* Get surface height and pressure... */
8213 const double zs = met->zs[ix][iy];
8214 const double lnps = log(met->ps[ix][iy]);
8215
8216 /* Get temperature and water vapor at the surface... */
8217 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
8218 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
8219 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
8220 const double h2os =
8221 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
8222 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
8223
8224 /* Upper part of profile... */
8225 met->z[ix][iy][ip0 + 1]
8226 = (float) (zs +
8227 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
8228 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
8229 for (int ip = ip0 + 2; ip < met->np; ip++)
8230 met->z[ix][iy][ip]
8231 = (float) (met->z[ix][iy][ip - 1] +
8232 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
8233 met->h2o[ix][iy][ip - 1], logp[ip],
8234 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8235
8236 /* Lower part of profile... */
8237 met->z[ix][iy][ip0]
8238 = (float) (zs +
8239 ZDIFF(lnps, ts, h2os, logp[ip0],
8240 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
8241 for (int ip = ip0 - 1; ip >= 0; ip--)
8242 met->z[ix][iy][ip]
8243 = (float) (met->z[ix][iy][ip + 1] +
8244 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
8245 met->h2o[ix][iy][ip + 1], logp[ip],
8246 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8247 }
8248
8249 /* Check control parameters... */
8250 if (dx == 0 || dy == 0)
8251 return;
8252
8253 /* Default smoothing parameters... */
8254 if (dx < 0 || dy < 0) {
8255 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
8256 dx = 3;
8257 dy = 2;
8258 } else {
8259 dx = 6;
8260 dy = 4;
8261 }
8262 }
8263
8264 /* Calculate weights for smoothing... */
8265 float ws[dx + 1][dy + 1];
8266#pragma omp parallel for default(shared) collapse(2)
8267 for (int ix = 0; ix <= dx; ix++)
8268 for (int iy = 0; iy < dy; iy++)
8269 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
8270 * (1.0f - (float) iy / (float) dy);
8271
8272 /* Copy data... */
8273#pragma omp parallel for default(shared) collapse(3)
8274 for (int ix = 0; ix < met->nx; ix++)
8275 for (int iy = 0; iy < met->ny; iy++)
8276 for (int ip = 0; ip < met->np; ip++)
8277 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
8278
8279 /* Horizontal smoothing... */
8280#pragma omp parallel for default(shared) collapse(3)
8281 for (int ip = 0; ip < met->np; ip++)
8282 for (int ix = 0; ix < met->nx; ix++)
8283 for (int iy = 0; iy < met->ny; iy++) {
8284 float res = 0, wsum = 0;
8285 int iy0 = MAX(iy - dy + 1, 0);
8286 int iy1 = MIN(iy + dy - 1, met->ny - 1);
8287 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
8288 int ix3 = ix2;
8289 if (ix3 < 0)
8290 ix3 += met->nx;
8291 else if (ix3 >= met->nx)
8292 ix3 -= met->nx;
8293 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
8294 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
8295 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
8296 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
8297 wsum += w;
8298 }
8299 }
8300 if (wsum > 0)
8301 met->z[ix][iy][ip] = res / wsum;
8302 else
8303 met->z[ix][iy][ip] = NAN;
8304 }
8305
8306 /* Free... */
8307 free(help);
8308}
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1911
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 8312 of file mptrac.c.

8317 {
8318
8319 char levname[LEN], tstr[10];
8320
8321 double rtime = 0, r, r2;
8322
8323 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
8324 year, mon, day, hour, min, sec;
8325
8326 size_t dimlen;
8327
8328 /* Set timer... */
8329 SELECT_TIMER("READ_MET_NC_GRID", "INPUT");
8330 LOG(2, "Read meteo grid information...");
8331
8332 /* MPTRAC meteo files... */
8333 if (!ctl->met_clams) {
8334
8335 /* Get time from filename... */
8336 met->time = time_from_filename(filename, 16);
8337
8338 /* Check time information from data file... */
8339 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8340 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
8341 NC(nc_get_var_double(ncid, varid, &rtime));
8342 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
8343 WARN("Time information in meteo file does not match filename!");
8344 } else
8345 WARN("Time information in meteo file is missing!");
8346 }
8347
8348 /* CLaMS meteo files... */
8349 else {
8350
8351 /* Read time from file... */
8352 NC_GET_DOUBLE("time", &rtime, 0);
8353
8354 /* Get time from filename (considering the century)... */
8355 if (rtime < 0)
8356 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
8357 else
8358 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
8359 year = atoi(tstr);
8360 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
8361 mon = atoi(tstr);
8362 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
8363 day = atoi(tstr);
8364 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
8365 hour = atoi(tstr);
8366 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
8367 }
8368
8369 /* Check time... */
8370 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8371 || day < 1 || day > 31 || hour < 0 || hour > 23)
8372 ERRMSG("Cannot read time from filename!");
8373 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
8374 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8375 met->time, year2, mon2, day2, hour2, min2);
8376
8377 /* Get vertical dimension... */
8378 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
8379 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
8380 ERRMSG
8381 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
8382
8383 NC(nc_inq_varndims(ncid, varid, &ndims));
8384 NC(nc_inq_vardimid(ncid, varid, dimids));
8385
8386 if (ndims == 4) {
8387 NC(nc_inq_dim
8388 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
8389 } else if (ndims == 3) {
8390 NC(nc_inq_dim
8391 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
8392 } else
8393 ERRMSG("Cannot determine vertical dimension!")
8394 met->np = (int) dimlen;
8395
8396 LOG(2, "Number of levels: %d", met->np);
8397 if (met->np < 2 || met->np > EP)
8398 ERRMSG("Number of levels out of range!");
8399
8400 if (!ctl->dd) {
8401
8402 /* Get grid dimensions... */
8403 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
8404 LOG(2, "Number of longitudes: %d", met->nx);
8405
8406 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
8407 LOG(2, "Number of latitudes: %d", met->ny);
8408
8409 /* Read longitudes and latitudes... */
8410 NC_GET_DOUBLE("lon", met->lon, 1);
8411 LOG(2, "Longitudes: %g, %g ... %g deg",
8412 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
8413 NC_GET_DOUBLE("lat", met->lat, 1);
8414 LOG(2, "Latitudes: %g, %g ... %g deg",
8415 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
8416
8417 } else {
8418
8419 /* Use 'naive', i.e. equidistant lat-lon domain decomposition... */
8420 read_met_nc_grid_dd_naive(dd, ctl, met, ncid);
8421
8422 }
8423
8424 /* Read pressure levels... */
8425 if (ctl->met_np <= 0) {
8426 NC_GET_DOUBLE(levname, met->p, 1);
8427 for (int ip = 0; ip < met->np; ip++)
8428 met->p[ip] /= 100.;
8429 LOG(2, "Altitude levels: %g, %g ... %g km",
8430 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8431 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8432 met->p[0], met->p[1], met->p[met->np - 1]);
8433 }
8434
8435 /* Read hybrid levels... */
8436 if (strcasecmp(levname, "hybrid") == 0)
8437 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
8438
8439 /* Read model level coefficients from file... */
8440 if (ctl->met_vert_coord == 2) {
8441 NC_GET_DOUBLE("hyam", met->hyam, 1);
8442 NC_GET_DOUBLE("hybm", met->hybm, 1);
8443 }
8444
8445 /* Copy model level coefficients from control parameters... */
8446 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
8447 if (ctl->met_nlev <= 0)
8448 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
8449 for (int ip = 0; ip < ctl->met_nlev; ip++) {
8450 met->hyam[ip] = ctl->met_lev_hyam[ip];
8451 met->hybm[ip] = ctl->met_lev_hybm[ip];
8452 }
8453 }
8454
8455 /* Calculate eta levels... */
8456 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
8457 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
8458 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
8459 ERRMSG("Eta levels must be ascending!");
8460 }
8461
8462 /* Check horizontal grid spacing... */
8463 for (int ix = 2; ix < met->nx; ix++)
8464 if (fabs
8465 (fabs(met->lon[ix] - met->lon[ix - 1]) -
8466 fabs(met->lon[1] - met->lon[0])) > 0.001)
8467 ERRMSG("No regular grid spacing in longitudes!");
8468 for (int iy = 2; iy < met->ny; iy++)
8469 if (fabs
8470 (fabs(met->lat[iy] - met->lat[iy - 1]) -
8471 fabs(met->lat[1] - met->lat[0])) > 0.001) {
8472 WARN("No regular grid spacing in latitudes!");
8473 break;
8474 }
8475}
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:11175
void read_met_nc_grid_dd_naive(dd_t *dd, const ctl_t *ctl, met_t *met, const int ncid)
Read meteorological grid data from a NetCDF file and set up subdomain decomposition with halos.
Definition: mptrac.c:9935
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:11274
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2481
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:2485
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3466
double eta[EP]
Model level eta values.
Definition: mptrac.h:3475
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3469
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3472
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 8479 of file mptrac.c.

8483 {
8484
8485 /* Set timer... */
8486 SELECT_TIMER("READ_MET_SURFACE", "INPUT");
8487 LOG(2, "Read surface data...");
8488
8489 /* Read surface pressure... */
8490 if (read_met_nc_2d
8491 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
8492 1.0f, 1)) {
8493 for (int ix = 0; ix < met->nx; ix++)
8494 for (int iy = 0; iy < met->ny; iy++)
8495 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8496 } else
8497 if (!read_met_nc_2d
8498 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
8499 0.01f, 1)) {
8500 WARN("Cannot not read surface pressure data (use lowest level)!");
8501 for (int ix = 0; ix < met->nx; ix++)
8502 for (int iy = 0; iy < met->ny; iy++)
8503 met->ps[ix][iy]
8504 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8505 }
8506
8507 /* MPTRAC meteo data... */
8508 if (ctl->met_clams == 0) {
8509
8510 /* Read geopotential height at the surface... */
8511 if (!read_met_nc_2d
8512 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8513 (float) (1. / (1000. * G0)), 1))
8514 if (!read_met_nc_2d
8515 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8516 (float) (1. / 1000.), 1))
8517 WARN("Cannot read surface geopotential height!");
8518 }
8519
8520 /* CLaMS meteo data... */
8521 else {
8522
8523 /* Read geopotential height at the surface
8524 (use lowermost level of 3-D data field)... */
8525 float *help;
8526 ALLOC(help, float,
8527 EX * EY * EP);
8528 memcpy(help, met->pl, sizeof(met->pl));
8529 if (!read_met_nc_3d
8530 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
8531 (float) (1e-3 / G0)))
8532 ERRMSG("Cannot read geopotential height!");
8533 for (int ix = 0; ix < met->nx; ix++)
8534 for (int iy = 0; iy < met->ny; iy++)
8535 met->zs[ix][iy] = met->pl[ix][iy][0];
8536 memcpy(met->pl, help, sizeof(met->pl));
8537 free(help);
8538 }
8539
8540 /* Read temperature at the surface... */
8541 if (!read_met_nc_2d
8542 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
8543 1))
8544 WARN("Cannot read surface temperature!");
8545
8546 /* Read zonal wind at the surface... */
8547 if (!read_met_nc_2d
8548 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
8549 met->us, 1.0, 1))
8550 WARN("Cannot read surface zonal wind!");
8551
8552 /* Read meridional wind at the surface... */
8553 if (!read_met_nc_2d
8554 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
8555 met->vs, 1.0, 1))
8556 WARN("Cannot read surface meridional wind!");
8557
8558 /* Read eastward turbulent surface stress... */
8559 if (!read_met_nc_2d
8560 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
8561 1.0, 1))
8562 WARN("Cannot read eastward turbulent surface stress!");
8563
8564 /* Read northward turbulent surface stress... */
8565 if (!read_met_nc_2d
8566 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
8567 1.0, 1))
8568 WARN("Cannot read nothward turbulent surface stress!");
8569
8570 /* Read surface sensible heat flux... */
8571 if (!read_met_nc_2d
8572 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
8573 1.0, 1))
8574 WARN("Cannot read surface sensible heat flux!");
8575
8576 /* Read land-sea mask... */
8577 if (!read_met_nc_2d
8578 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
8579 1.0, 1))
8580 WARN("Cannot read land-sea mask!");
8581
8582 /* Read sea surface temperature... */
8583 if (!read_met_nc_2d
8584 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
8585 1.0, 1))
8586 WARN("Cannot read sea surface temperature!");
8587
8588 /* Read PBL... */
8589 if (ctl->met_pbl == 0)
8590 if (!read_met_nc_2d
8591 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8592 0.01f, 1))
8593 WARN("Cannot read planetary boundary layer pressure!");
8594 if (ctl->met_pbl == 1)
8595 if (!read_met_nc_2d
8596 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8597 0.001f, 1))
8598 WARN("Cannot read planetary boundary layer height!");
8599
8600 /* Read CAPE... */
8601 if (ctl->met_cape == 0)
8602 if (!read_met_nc_2d
8603 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
8604 met->cape, 1.0, 1))
8605 WARN("Cannot read CAPE!");
8606
8607 /* Read CIN... */
8608 if (ctl->met_cape == 0)
8609 if (!read_met_nc_2d
8610 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
8611 1.0, 1))
8612 WARN("Cannot read convective inhibition!");
8613}
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:8814
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:9076
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 8617 of file mptrac.c.

8621 {
8622
8623 /* Set timer... */
8624 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT");
8625 LOG(2, "Read level data...");
8626
8627 /* Read temperature... */
8628 if (!read_met_nc_3d
8629 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
8630 ERRMSG("Cannot read temperature!");
8631
8632 /* Read horizontal wind and vertical velocity... */
8633 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
8634 ERRMSG("Cannot read zonal wind!");
8635 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
8636 ERRMSG("Cannot read meridional wind!");
8637 if (!read_met_nc_3d
8638 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
8639 WARN("Cannot read vertical velocity!");
8640
8641 /* Read water vapor... */
8642 if (!ctl->met_relhum) {
8643 if (!read_met_nc_3d
8644 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
8645 (float) (MA / MH2O)))
8646 WARN("Cannot read specific humidity!");
8647 } else {
8648 if (!read_met_nc_3d
8649 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
8650 WARN("Cannot read relative humidity!");
8651#pragma omp parallel for default(shared) collapse(2)
8652 for (int ix = 0; ix < met->nx; ix++)
8653 for (int iy = 0; iy < met->ny; iy++)
8654 for (int ip = 0; ip < met->np; ip++) {
8655 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
8656 met->h2o[ix][iy][ip] =
8657 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
8658 }
8659 }
8660
8661 /* Read ozone... */
8662 if (!read_met_nc_3d
8663 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
8664 (float) (MA / MO3)))
8665 WARN("Cannot read ozone data!");
8666
8667 /* Read cloud data... */
8668 if (!read_met_nc_3d
8669 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
8670 WARN("Cannot read cloud liquid water content!");
8671 if (!read_met_nc_3d
8672 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
8673 WARN("Cannot read cloud rain water content!");
8674 if (!read_met_nc_3d
8675 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
8676 WARN("Cannot read cloud ice water content!");
8677 if (!read_met_nc_3d
8678 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
8679 WARN("Cannot read cloud snow water content!");
8680 if (!read_met_nc_3d
8681 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
8682 WARN("Cannot read cloud cover!");
8683
8684 /* Read zeta and zeta_dot... */
8685 if (ctl->advect_vert_coord == 1) {
8686 if (!read_met_nc_3d
8687 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
8688 WARN("Cannot read ZETA!");
8689 if (!read_met_nc_3d
8690 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
8691 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
8692 WARN("Cannot read ZETA_DOT!");
8693 }
8694
8695 /* Read eta and eta_dot... */
8696 else if (ctl->advect_vert_coord == 3) {
8697#pragma omp parallel for default(shared)
8698 for (int ix = 0; ix < met->nx; ix++)
8699 for (int iy = 0; iy < met->ny; iy++)
8700 for (int ip = 0; ip < met->np; ip++)
8701 met->zetal[ix][iy][ip] =
8702 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
8703 if (!read_met_nc_3d
8704 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
8705 1.0))
8706 WARN("Cannot read eta vertical velocity!");
8707 }
8708
8709 /* Store velocities on model levels... */
8710 if (ctl->met_vert_coord != 0) {
8711#pragma omp parallel for default(shared)
8712 for (int ix = 0; ix < met->nx; ix++)
8713 for (int iy = 0; iy < met->ny; iy++)
8714 for (int ip = 0; ip < met->np; ip++) {
8715 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
8716 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
8717 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
8718 }
8719
8720 /* Save number of model levels... */
8721 met->npl = met->np;
8722 }
8723
8724 /* Get pressure on model levels... */
8725 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
8726
8727 /* Read 3-D pressure field... */
8728 if (ctl->met_vert_coord == 1) {
8729 if (!read_met_nc_3d
8730 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
8731 0.01f))
8732 if (!read_met_nc_3d
8733 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
8734 ERRMSG("Cannot read pressure on model levels!");
8735 }
8736
8737 /* Use a and b coefficients for full levels (at layer midpoints)... */
8738 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
8739
8740 /* Check number of levels... */
8741 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
8742 ERRMSG("Mismatch in number of model levels!");
8743
8744 /* Calculate pressure... */
8745 for (int ix = 0; ix < met->nx; ix++)
8746 for (int iy = 0; iy < met->ny; iy++)
8747 for (int ip = 0; ip < met->np; ip++)
8748 met->pl[ix][iy][ip] =
8749 (float) (met->hyam[ip] / 100. +
8750 met->hybm[ip] * met->ps[ix][iy]);
8751 }
8752
8753 /* Use a and b coefficients for half levels (at layer interfaces)... */
8754 else if (ctl->met_vert_coord == 4) {
8755
8756 /* Check number of levels... */
8757 if (met->np + 1 != ctl->met_nlev)
8758 ERRMSG("Mismatch in number of model levels!");
8759
8760 /* Calculate pressure... */
8761#pragma omp parallel for default(shared) collapse(2)
8762 for (int ix = 0; ix < met->nx; ix++)
8763 for (int iy = 0; iy < met->ny; iy++)
8764 for (int ip = 0; ip < met->np; ip++) {
8765 const double p0 =
8766 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
8767 const double p1 =
8768 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
8769 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
8770 }
8771 }
8772
8773 /* Check ordering of pressure levels... */
8774 for (int ix = 0; ix < met->nx; ix++)
8775 for (int iy = 0; iy < met->ny; iy++)
8776 for (int ip = 1; ip < met->np; ip++)
8777 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
8778 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
8779 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
8780 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
8781 ERRMSG("Pressure profiles are not monotonic!");
8782 }
8783
8784 /* Interpolate from model levels to pressure levels... */
8785 if (ctl->met_np > 0) {
8786
8787 /* Interpolate variables... */
8788 read_met_ml2pl(ctl, met, met->t, "T");
8789 read_met_ml2pl(ctl, met, met->u, "U");
8790 read_met_ml2pl(ctl, met, met->v, "V");
8791 read_met_ml2pl(ctl, met, met->w, "W");
8792 read_met_ml2pl(ctl, met, met->h2o, "H2O");
8793 read_met_ml2pl(ctl, met, met->o3, "O3");
8794 read_met_ml2pl(ctl, met, met->lwc, "LWC");
8795 read_met_ml2pl(ctl, met, met->rwc, "RWC");
8796 read_met_ml2pl(ctl, met, met->iwc, "IWC");
8797 read_met_ml2pl(ctl, met, met->swc, "SWC");
8798 read_met_ml2pl(ctl, met, met->cc, "CC");
8799
8800 /* Set new pressure levels... */
8801 met->np = ctl->met_np;
8802 for (int ip = 0; ip < met->np; ip++)
8803 met->p[ip] = ctl->met_p[ip];
8804 }
8805
8806 /* Check ordering of pressure levels... */
8807 for (int ip = 1; ip < met->np; ip++)
8808 if (met->p[ip - 1] < met->p[ip])
8809 ERRMSG("Pressure levels must be descending!");
8810}
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:9768
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:244
#define MO3
Molar mass of ozone [g/mol].
Definition: mptrac.h:249
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 8814 of file mptrac.c.

8827 {
8828
8829 char varsel[LEN];
8830
8831 float offset, scalfac;
8832
8833 int varid;
8834
8835 /* Check if variable exists... */
8836 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8837 sprintf(varsel, "%s", varname);
8838 else if (varname2 != NULL
8839 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8840 sprintf(varsel, "%s", varname2);
8841 else if (varname3 != NULL
8842 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8843 sprintf(varsel, "%s", varname3);
8844 else if (varname4 != NULL
8845 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8846 sprintf(varsel, "%s", varname4);
8847 else if (varname5 != NULL
8848 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
8849 sprintf(varsel, "%s", varname5);
8850 else if (varname6 != NULL
8851 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
8852 sprintf(varsel, "%s", varname6);
8853 else
8854 return 0;
8855
8856 /* Read packed data... */
8857 if (ctl->met_nc_scale && !ctl->dd
8858 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8859 && nc_get_att_float(ncid, varid, "scale_factor",
8860 &scalfac) == NC_NOERR) {
8861
8862 /* Allocate... */
8863 short *help;
8864 ALLOC(help, short,
8865 EX * EY * EP);
8866
8867 /* Read fill value and missing value... */
8868 short fillval, missval;
8869 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8870 fillval = 0;
8871 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
8872 missval = 0;
8873
8874 /* Write info... */
8875 LOG(2, "Read 2-D variable: %s"
8876 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
8877 varsel, fillval, missval, scalfac, offset);
8878
8879 /* Read data... */
8880 NC(nc_get_var_short(ncid, varid, help));
8881
8882 /* Check meteo data layout... */
8883 if (ctl->met_convention != 0)
8884 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
8885
8886 /* Copy and check data... */
8887 omp_set_dynamic(1);
8888#pragma omp parallel for default(shared)
8889 for (int ix = 0; ix < met->nx; ix++)
8890 for (int iy = 0; iy < met->ny; iy++) {
8891 if (init)
8892 dest[ix][iy] = 0;
8893 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
8894 if ((fillval == 0 || aux != fillval)
8895 && (missval == 0 || aux != missval)
8896 && fabsf(aux * scalfac + offset) < 1e14f)
8897 dest[ix][iy] += scl * (aux * scalfac + offset);
8898 else
8899 dest[ix][iy] = 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);
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 2-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: 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 if (init)
8938 dest[ix][iy] = 0;
8939 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
8940 if ((fillval == 0 || aux != fillval)
8941 && (missval == 0 || aux != missval)
8942 && fabsf(aux) < 1e14f)
8943 dest[ix][iy] += scl * aux;
8944 else
8945 dest[ix][iy] = NAN;
8946 }
8947 omp_set_dynamic(0);
8948
8949 } else {
8950
8951 /* Copy and check data (ordering: lon, lat)... */
8952 omp_set_dynamic(1);
8953#pragma omp parallel for default(shared)
8954 for (int iy = 0; iy < met->ny; iy++)
8955 for (int ix = 0; ix < met->nx; ix++) {
8956 if (init)
8957 dest[ix][iy] = 0;
8958 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
8959 if ((fillval == 0 || aux != fillval)
8960 && (missval == 0 || aux != missval)
8961 && fabsf(aux) < 1e14f)
8962 dest[ix][iy] += scl * aux;
8963 else
8964 dest[ix][iy] = NAN;
8965 }
8966 omp_set_dynamic(0);
8967 }
8968
8969 /* Free... */
8970 free(help);
8971
8972 }
8973 /* Domain decomposed data... */
8974 else {
8975
8976 /* Read fill value and missing value... */
8977 float fillval, missval;
8978 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8979 fillval = 0;
8980 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8981 missval = 0;
8982
8983 /* Write info... */
8984 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8985 varsel, fillval, missval);
8986
8987 /* Define hyperslab... */
8988 float *help;
8989 size_t help_subdomain_start[3];
8990 size_t help_subdomain_count[3];
8991
8992 help_subdomain_start[0] = 0;
8993 help_subdomain_start[1] = dd->subdomain_start[2];
8994 help_subdomain_start[2] = dd->subdomain_start[3];
8995
8996 help_subdomain_count[0] = 1;
8997 help_subdomain_count[1] = dd->subdomain_count[2]; //y
8998 help_subdomain_count[2] = dd->subdomain_count[3]; //x
8999
9000 ALLOC(help, float,
9001 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]
9002 );
9003
9004 /* Read data... */
9005 NC(nc_get_vara_float
9006 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
9007
9008 /* Read halos at boundaries... */
9009 size_t help_halo_bnd_start[3];
9010 size_t help_halo_bnd_count[3];
9011
9012 help_halo_bnd_start[0] = 0;
9013 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
9014 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
9015
9016 help_halo_bnd_count[0] = 1;
9017 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
9018 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
9019
9020 float *help_halo;
9021 ALLOC(help_halo, float,
9022 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
9023 NC(nc_get_vara_float
9024 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
9025
9026 /* Check meteo data layout... */
9027 if (ctl->met_convention == 0) {
9028 /* Copy and check data (ordering: lat, lon)... */
9029#pragma omp parallel for default(shared) num_threads(12)
9030 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
9031 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
9032 if (init == 1)
9033 dest[ix + dd->halo_offset_start][iy] = 0;
9034 const float aux =
9035 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
9036 if ((fillval == 0 || aux != fillval)
9037 && (missval == 0 || aux != missval)
9038 && fabsf(aux) < 1e14f) {
9039 dest[ix + dd->halo_offset_start][iy] += scl * aux;
9040 } else
9041 dest[ix + dd->halo_offset_start][iy] = NAN;
9042 }
9043
9044 /* Copy and check data (ordering: lat, lon)... */
9045#pragma omp parallel for default(shared) num_threads(12)
9046 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
9047 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
9048 if (init == 1)
9049 dest[ix + dd->halo_offset_end][iy] = 0;
9050 const float aux =
9051 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
9052 if ((fillval == 0 || aux != fillval)
9053 && (missval == 0 || aux != missval)
9054 && fabsf(aux) < 1e14f)
9055 dest[ix + dd->halo_offset_end][iy] += scl * aux;
9056 else {
9057 dest[ix + dd->halo_offset_end][iy] = NAN;
9058 }
9059 }
9060
9061 } else {
9062 ERRMSG("Domain decomposition with data convection incompatible!");
9063 }
9064
9065 /* Free... */
9066 free(help);
9067 free(help_halo);
9068 }
9069
9070 /* Return... */
9071 return 1;
9072}
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2495
size_t halo_bnd_count[4]
Hyperslab of boundary halos count.
Definition: mptrac.h:3659
int halo_offset_end
Hyperslab of boundary halos count.
Definition: mptrac.h:3665
size_t halo_bnd_start[4]
Hyperslab of boundary halos start.
Definition: mptrac.h:3656
int halo_offset_start
Hyperslab of boundary halos count.
Definition: mptrac.h:3662
size_t subdomain_count[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3653
size_t subdomain_start[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3650

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

9086 {
9087
9088 SELECT_TIMER("read_met_nc_3d", "INPUT");
9089
9090 char varsel[LEN];
9091
9092 float offset, scalfac;
9093
9094 int varid;
9095
9096 /* Check if variable exists... */
9097 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9098 sprintf(varsel, "%s", varname);
9099 else if (varname2 != NULL
9100 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9101 sprintf(varsel, "%s", varname2);
9102 else if (varname3 != NULL
9103 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9104 sprintf(varsel, "%s", varname3);
9105 else if (varname4 != NULL
9106 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9107 sprintf(varsel, "%s", varname4);
9108 else
9109 return 0;
9110
9111 if (ctl->met_nc_scale && !ctl->dd
9112 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9113 && nc_get_att_float(ncid, varid, "scale_factor",
9114 &scalfac) == NC_NOERR) {
9115
9116 /* Allocate... */
9117 short *help;
9118 ALLOC(help, short,
9119 EX * EY * EP);
9120
9121 /* Read fill value and missing value... */
9122 short fillval, missval;
9123 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9124 fillval = 0;
9125 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9126 missval = 0;
9127
9128 /* Write info... */
9129 LOG(2, "Read 3-D variable: %s "
9130 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9131 varsel, fillval, missval, scalfac, offset);
9132
9133 /* Read data... */
9134 NC(nc_get_var_short(ncid, varid, help));
9135
9136 /* Check meteo data layout... */
9137 if (ctl->met_convention != 0)
9138 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9139
9140 /* Copy and check data... */
9141 omp_set_dynamic(1);
9142#pragma omp parallel for default(shared)
9143 for (int ix = 0; ix < met->nx; ix++)
9144 for (int iy = 0; iy < met->ny; iy++)
9145 for (int ip = 0; ip < met->np; ip++) {
9146 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9147 if ((fillval == 0 || aux != fillval)
9148 && (missval == 0 || aux != missval)
9149 && fabsf(aux * scalfac + offset) < 1e14f)
9150 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
9151 else
9152 dest[ix][iy][ip] = NAN;
9153 }
9154 omp_set_dynamic(0);
9155
9156 /* Free... */
9157 free(help);
9158 }
9159
9160 /* Unpacked data... */
9161 else if (!ctl->dd) {
9162
9163 /* Allocate... */
9164 float *help;
9165 ALLOC(help, float,
9166 EX * EY * EP);
9167
9168 /* Read fill value and missing value... */
9169 float fillval, missval;
9170 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9171 fillval = 0;
9172 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9173 missval = 0;
9174
9175 /* Write info... */
9176 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9177 varsel, fillval, missval);
9178
9179 /* Read data... */
9180 NC(nc_get_var_float(ncid, varid, help));
9181
9182 /* Check meteo data layout... */
9183 if (ctl->met_convention == 0) {
9184
9185 /* Copy and check data (ordering: lev, lat, lon)... */
9186 omp_set_dynamic(1);
9187#pragma omp parallel for default(shared)
9188 for (int ix = 0; ix < met->nx; ix++)
9189 for (int iy = 0; iy < met->ny; iy++)
9190 for (int ip = 0; ip < met->np; ip++) {
9191 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9192 if ((fillval == 0 || aux != fillval)
9193 && (missval == 0 || aux != missval)
9194 && fabsf(aux) < 1e14f)
9195 dest[ix][iy][ip] = scl * aux;
9196 else
9197 dest[ix][iy][ip] = NAN;
9198 }
9199 omp_set_dynamic(0);
9200
9201 } else {
9202
9203 /* Copy and check data (ordering: lon, lat, lev)... */
9204 omp_set_dynamic(1);
9205#pragma omp parallel for default(shared)
9206 for (int ip = 0; ip < met->np; ip++)
9207 for (int iy = 0; iy < met->ny; iy++)
9208 for (int ix = 0; ix < met->nx; ix++) {
9209 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9210 if ((fillval == 0 || aux != fillval)
9211 && (missval == 0 || aux != missval)
9212 && fabsf(aux) < 1e14f)
9213 dest[ix][iy][ip] = scl * aux;
9214 else
9215 dest[ix][iy][ip] = NAN;
9216 }
9217 omp_set_dynamic(0);
9218 }
9219
9220 /* Free... */
9221 free(help);
9222
9223 }
9224 /* Domain decomposed data... */
9225 else {
9226
9227 /* Read fill value and missing value... */
9228 float fillval, missval;
9229 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9230 fillval = 0;
9231 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9232 missval = 0;
9233
9234 /* Write info... */
9235 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9236 varsel, fillval, missval);
9237
9238 SELECT_TIMER("read_met_nc_3d_CP1", "INPUT");
9239
9240 /* Define hyperslab... */
9241
9242 /* Allocate... */
9243 float *help;
9244 ALLOC(help, float,
9245 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
9246 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
9247
9248 SELECT_TIMER("read_met_nc_3d_CP2", "INPUT");
9249
9250 /* Use default NetCDF parallel I/O behavior */
9251 NC(nc_get_vara_float
9252 (ncid, varid, dd->subdomain_start, dd->subdomain_count, help));
9253
9254 /* Read halos separately at boundaries... */
9255 float *help_halo;
9256 ALLOC(help_halo, float,
9257 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
9258 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
9259
9260 SELECT_TIMER("read_met_nc_3d_CP3", "INPUT");
9261
9262 /* Halo read also uses independent access */
9263 NC(nc_get_vara_float(ncid,
9264 varid,
9265 dd->halo_bnd_start, dd->halo_bnd_count, help_halo));
9266
9267 SELECT_TIMER("read_met_nc_3d_CP4", "INPUT");
9268
9269 /* Check meteo data layout... */
9270 if (ctl->met_convention == 0) {
9271 /* Copy and check data (ordering: lev, lat, lon)... */
9272#pragma omp parallel for default(shared) num_threads(12)
9273 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9274 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9275 for (int ip = 0; ip < met->np; ip++) {
9276 const float aux =
9277 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
9278 (int) dd->subdomain_count[3])];
9279 if ((fillval == 0 || aux != fillval)
9280 && (missval == 0 || aux != missval)
9281 && fabsf(aux) < 1e14f)
9282 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9283 else
9284 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9285 }
9286
9287#pragma omp parallel for default(shared) num_threads(12)
9288 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9289 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9290 for (int ip = 0; ip < met->np; ip++) {
9291 const float aux =
9292 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
9293 (int) dd->halo_bnd_count[3])];
9294 if ((fillval == 0 || aux != fillval)
9295 && (missval == 0 || aux != missval)
9296 && fabsf(aux) < 1e14f)
9297 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9298 else
9299 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9300 }
9301
9302 } else {
9303
9304 /* Copy and check data (ordering: lon, lat, lev)... */
9305#pragma omp parallel for default(shared) num_threads(12)
9306 for (int ip = 0; ip < met->np; ip++)
9307 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9308 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
9309 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9310 if ((fillval == 0 || aux != fillval)
9311 && (missval == 0 || aux != missval)
9312 && fabsf(aux) < 1e14f)
9313 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9314 else
9315 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9316 }
9317
9318#pragma omp parallel for default(shared) num_threads(12)
9319 for (int ip = 0; ip < met->np; ip++)
9320 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9321 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
9322 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9323 if ((fillval == 0 || aux != fillval)
9324 && (missval == 0 || aux != missval)
9325 && fabsf(aux) < 1e14f)
9326 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9327 else
9328 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9329 }
9330 }
9331
9332 /* Free... */
9333 free(help);
9334 free(help_halo);
9335 }
9336
9337 /* Return... */
9338 return 1;
9339}

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

9772 {
9773
9774 double aux[EP], p[EP];
9775
9776 /* Set timer... */
9777 SELECT_TIMER("READ_MET_ML2PL", "METPROC");
9778 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
9779
9780 /* Loop over columns... */
9781#pragma omp parallel for default(shared) private(aux,p) collapse(2)
9782 for (int ix = 0; ix < met->nx; ix++)
9783 for (int iy = 0; iy < met->ny; iy++) {
9784
9785 /* Copy pressure profile... */
9786 for (int ip = 0; ip < met->np; ip++)
9787 p[ip] = met->pl[ix][iy][ip];
9788
9789 /* Interpolate... */
9790 for (int ip = 0; ip < ctl->met_np; ip++) {
9791 double pt = ctl->met_p[ip];
9792 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
9793 pt = p[0];
9794 else if ((pt > p[met->np - 1] && p[1] > p[0])
9795 || (pt < p[met->np - 1] && p[1] < p[0]))
9796 pt = p[met->np - 1];
9797 const int ip2 = locate_irr(p, met->np, pt);
9798 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
9799 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
9800 }
9801
9802 /* Copy data... */
9803 for (int ip = 0; ip < ctl->met_np; ip++)
9804 var[ix][iy][ip] = (float) aux[ip];
9805 }
9806}
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 9810 of file mptrac.c.

9812 {
9813
9814 /* Check parameters... */
9815 if (ctl->advect_vert_coord != 1)
9816 return;
9817
9818 /* Set timer... */
9819 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC");
9820 LOG(2, "Make zeta profiles monotone...");
9821
9822 /* Create monotone zeta profiles... */
9823#pragma omp parallel for default(shared) collapse(2)
9824 for (int i = 0; i < met->nx; i++)
9825 for (int j = 0; j < met->ny; j++) {
9826 int k = 1;
9827
9828 while (k < met->npl) { /* Check if there is an inversion at level k... */
9829 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
9830 /* Find the upper level k+l over the inversion... */
9831 int l = 0;
9832 do {
9833 l++;
9834 }
9835 while ((met->zetal[i][j][k - 1] >=
9836 met->zetal[i][j][k + l]) & (k + l < met->npl));
9837
9838 /* Interpolate linear between the top and bottom
9839 of the inversion... */
9840 float s =
9841 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
9842 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9843
9844 for (int m = k; m < k + l; m++) {
9845 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9846 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
9847 }
9848
9849 /* Search for more inversions above the last inversion ... */
9850 k = k + l;
9851 } else {
9852 k++;
9853 }
9854 }
9855 }
9856
9857 /* Create monotone pressure profiles... */
9858#pragma omp parallel for default(shared) collapse(2)
9859 for (int i = 0; i < met->nx; i++)
9860 for (int j = 0; j < met->ny; j++) {
9861 int k = 1;
9862
9863 while (k < met->npl) { /* Check if there is an inversion at level k... */
9864 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
9865
9866 /* Find the upper level k+l over the inversion... */
9867 int l = 0;
9868 do {
9869 l++;
9870 }
9871 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
9872 met->npl));
9873
9874 /* Interpolate linear between the top and bottom
9875 of the inversion... */
9876 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
9877 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9878
9879 for (int m = k; m < k + l; m++) {
9880 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9881 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
9882 }
9883
9884 /* Search for more inversions above the last inversion ... */
9885 k += l;
9886 } else {
9887 k++;
9888 }
9889 }
9890 }
9891}

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

9899 {
9900
9901 int ncid;
9902
9903 /* Open file... */
9904#ifdef DD
9905 if (ctl->dd) {
9906 NC(nc_open_par
9907 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
9908 &ncid))
9909 }
9910#else
9911 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
9912 WARN("Cannot open file!");
9913 return 0;
9914 }
9915#endif
9916
9917 /* Read coordinates of meteo data... */
9918 read_met_nc_grid(filename, ncid, ctl, met, dd);
9919
9920 /* Read surface data... */
9921 read_met_nc_surface(ncid, ctl, met, dd);
9922
9923 /* Read meteo data on vertical levels... */
9924 read_met_nc_levels(ncid, ctl, met, dd);
9925
9926 /* Close file... */
9927 NC(nc_close(ncid));
9928
9929 /* Return success... */
9930 return 1;
9931}
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:8617
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:8479
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:8312
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 data from a NetCDF file and set up subdomain decomposition with halos.

This function initializes the distributed grid decomposition for meteorological data stored in a NetCDF file. It queries global grid dimensions (longitude, latitude), determines the local subdomain size for each MPI rank, and sets up hyperslabs for reading data in parallel. It also constructs halo regions for subdomain boundaries, ensuring periodic wrap-around in the zonal direction when applicable.

The function adjusts subdomain sizes at the right and bottom edges of the global grid to exactly fit the full domain. It then updates the met_t structure with the local longitude and latitude arrays for the subdomain including halos, and stores decomposition metadata in the dd_t structure.

Parameters
[out]ddPointer to a dd_t structure. On output, it contains:
  • MPI rank and size
  • subdomain start indices and counts
  • halo start indices and counts
  • subdomain longitude and latitude ranges
  • halo offsets
[in]ctlPointer to a ctl_t structure containing decomposition parameters:
  • ctl->dd_subdomains_zonal
  • ctl->dd_subdomains_meridional
  • ctl->dd_halos_size
[out]metPointer to a met_t structure. On output, it contains:
  • subdomain grid dimensions (nx, ny, np)
  • longitude and latitude arrays restricted to the subdomain including halos.
[in]ncidNetCDF file ID obtained from a call to nc_open.
Note
  • Requires MPI if compiled with -DMPI.
  • Assumes latitude is ordered from 90 to -90 (descending). A warning is issued if latitude range is positive.
  • Allocates and frees temporary arrays for global longitude and latitude.
  • Halo setup ensures overlap with neighboring subdomains, and handles wrap-around at the left and right boundaries.
  • For periodic grids, the longitude range is assumed to be 360°.
Author
Jan Clemens

Definition at line 9935 of file mptrac.c.

9939 {
9940
9941 int varid;
9942
9943 /* Get the MPI information... */
9944#ifdef MPI
9945 MPI_Comm_rank(MPI_COMM_WORLD, &dd->rank);
9946 MPI_Comm_size(MPI_COMM_WORLD, &dd->size);
9947#endif
9948
9949 int help_nx_glob;
9950 int help_ny_glob;
9951
9952 /* Get grid dimensions... */
9953 NC_INQ_DIM("lon", &help_nx_glob, 0, 0, 0);
9954 LOG(2, "Number of longitudes: %d", help_nx_glob);
9955 met->nx = (int) floor(help_nx_glob / ctl->dd_subdomains_zonal);
9956
9957 NC_INQ_DIM("lat", &help_ny_glob, 0, 0, 0);
9958 LOG(2, "Number of latitudes: %d", help_ny_glob);
9959 met->ny = (int) floor(help_ny_glob / ctl->dd_subdomains_meridional);
9960
9961 double *help_lon_glob;
9962 double *help_lat_glob;
9963 ALLOC(help_lon_glob, double,
9964 help_nx_glob);
9965 ALLOC(help_lat_glob, double,
9966 help_ny_glob);
9967
9968 /* Read global longitudes and latitudes... */
9969 NC_GET_DOUBLE("lon", help_lon_glob, 1);
9970 LOG(2, "Longitudes: %g, %g ... %g deg",
9971 help_lon_glob[0], help_lon_glob[1], help_lon_glob[help_nx_glob - 1]);
9972 NC_GET_DOUBLE("lat", help_lat_glob, 1);
9973 LOG(2, "Latitudes: %g, %g ... %g deg",
9974 help_lat_glob[0], help_lat_glob[1], help_lat_glob[help_ny_glob - 1]);
9975
9976 /* Determine hyperslabs for reading the data in parallel... */
9977
9978 /* Check for edge cases... */
9979 int left = (dd->rank <= ctl->dd_subdomains_meridional - 1);
9980 int right = (dd->rank >= dd->size - ctl->dd_subdomains_meridional);
9981 int top = (dd->rank % ctl->dd_subdomains_meridional == 0);
9982 int bottom =
9983 (dd->rank % ctl->dd_subdomains_meridional ==
9984 ctl->dd_subdomains_meridional - 1);
9985
9986 /* Set the hyperslab for the subdomain... */
9987 dd->subdomain_start[0] = 0;
9988 dd->subdomain_start[1] = 0;
9989 dd->subdomain_start[2] =
9990 (size_t) ((dd->rank % ctl->dd_subdomains_meridional) * met->ny);
9991 dd->subdomain_start[3] =
9992 (size_t) (floor(dd->rank / ctl->dd_subdomains_meridional) * met->nx);
9993
9994 /* Extend subdomains at the right and bottom to fit the full domain. */
9995 if (right) {
9996 int gap = help_nx_glob - ctl->dd_subdomains_zonal * met->nx;
9997 if (gap > 0) {
9998 met->nx = met->nx + gap;
9999 WARN("Extended subdomains at the right to fit to full domain.");
10000 }
10001 }
10002 if (bottom) {
10003 int gap = help_ny_glob - ctl->dd_subdomains_meridional * met->ny;
10004 if (gap > 0) {
10005 met->ny = met->ny + gap;
10006 WARN("Extended subdomains at the bottom to fit to full domain.");
10007 }
10008 }
10009
10010 /* Block-size, i.e. count */
10011 dd->subdomain_count[0] = 1;
10012 dd->subdomain_count[1] = (size_t) met->np;
10013 dd->subdomain_count[2] = (size_t) met->ny;
10014 dd->subdomain_count[3] = (size_t) met->nx;
10015
10016 /* Create halos and include them into the subdomain... */
10017 if (!left && !right) {
10018 // If we are not at the left or right edge extend in zonal direction...
10019 // Move the start one point to the left...
10020 dd->subdomain_count[3] =
10021 dd->subdomain_count[3] + (size_t) (ctl->dd_halos_size * 2);
10022 dd->subdomain_start[3] =
10023 dd->subdomain_start[3] - (size_t) ctl->dd_halos_size;
10024 } else {
10025 // If we are at the left or right edge, extend only in one zonal direction...
10026 dd->subdomain_count[3] =
10027 dd->subdomain_count[3] + (size_t) ctl->dd_halos_size;
10028 if (!left)
10029 // If we are not at the left edge, move the start to the left...
10030 dd->subdomain_start[3] =
10031 dd->subdomain_start[3] - (size_t) ctl->dd_halos_size;
10032 }
10033
10034 if (!top && !bottom) {
10035 // If we are not at the upper or lower edge extend in meridional direction...
10036 // Move the start point one point down...
10037 dd->subdomain_count[2] =
10038 dd->subdomain_count[2] + (size_t) (ctl->dd_halos_size * 2);
10039 dd->subdomain_start[2] =
10040 dd->subdomain_start[2] - (size_t) ctl->dd_halos_size;
10041 } else {
10042 // If we are at the top or the lower edge only extend in one mer. direction...
10043 dd->subdomain_count[2] =
10044 dd->subdomain_count[2] + (size_t) ctl->dd_halos_size;
10045 if (!top)
10046 // If we are not at the top, move the start one upward...
10047 dd->subdomain_start[2] =
10048 dd->subdomain_start[2] - (size_t) ctl->dd_halos_size;
10049 }
10050
10051 /* Set boundary halo hyperslabs ... */
10052 double lon_shift = 0;
10053 if (left || right) {
10054
10055 met->nx = met->nx + ctl->dd_halos_size;
10056
10057 dd->halo_bnd_start[0] = 0;
10058 dd->halo_bnd_start[1] = 0;
10059 dd->halo_bnd_start[3] = (size_t) (left ? (help_nx_glob - ctl->dd_halos_size) : (0)); //x
10060 dd->halo_bnd_start[2] = dd->subdomain_start[2]; //y
10061
10062 dd->halo_bnd_count[0] = 1;
10063 dd->halo_bnd_count[1] = (size_t) met->np;
10064 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
10065 dd->halo_bnd_count[2] =
10066 (size_t) met->ny +
10067 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
10068
10069 dd->halo_offset_start = (left ? (int) dd->halo_bnd_count[3] : 0);
10070 dd->halo_offset_end = (left ? 0 : (int) dd->subdomain_count[3]);
10071 lon_shift = (left ? -360 : 360);
10072
10073 } else {
10074
10075 dd->halo_bnd_start[0] = 0;
10076 dd->halo_bnd_start[1] = 0;
10077 dd->halo_bnd_start[3] = 0;
10078 dd->halo_bnd_start[2] = 0;
10079
10080 dd->halo_bnd_count[0] = 0;
10081 dd->halo_bnd_count[1] = 0;
10082 dd->halo_bnd_count[3] = 0;
10083 dd->halo_bnd_count[2] = 0;
10084 }
10085
10086 /* Get the range of the entire meteodata... */
10087 double lon_range = 360;
10088 double lat_range = help_lat_glob[help_ny_glob - 1] - help_lat_glob[0];
10089
10090 /* Focus on subdomain latitudes and longitudes... */
10091 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10092 met->lat[iy] = help_lat_glob[(int) dd->subdomain_start[2] + iy];
10093
10094 /* Focus on subdomain longitudes... */
10095 /* Keep space at the beginning or end of the array for halo... */
10096 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10097 met->lon[ix + dd->halo_offset_start] =
10098 help_lon_glob[(int) dd->subdomain_start[3] + ix];
10099
10100 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10101 met->lon[ix + dd->halo_offset_end] =
10102 help_lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
10103
10104 /* Reset the grid dimensions... */
10105 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
10106 met->ny = (int) dd->subdomain_count[2];
10107
10108 /* Determine subdomain edges... */
10109 dd->subdomain_lon_min = floor(dd->rank / ctl->dd_subdomains_meridional)
10110 * (lon_range) / (double) ctl->dd_subdomains_zonal;
10111 dd->subdomain_lon_max = dd->subdomain_lon_min
10112 + (lon_range) / (double) ctl->dd_subdomains_zonal;
10113
10114 /* Latitudes in descending order (90 to -90) */
10115 if (lat_range < 0) {
10116 dd->subdomain_lat_max = 90 + (dd->rank % ctl->dd_subdomains_meridional)
10117 * (lat_range) / (double) ctl->dd_subdomains_meridional;
10119 + (lat_range) / (double) ctl->dd_subdomains_meridional;
10120 } else {
10121 WARN
10122 ("lat_range > 0, but is expected to be negative, i.e. latitudes should range from 90 to -90")
10123 dd->subdomain_lat_min = -90 + (dd->rank % ctl->dd_subdomains_meridional)
10124 * (lat_range) / (double) ctl->dd_subdomains_meridional;
10125 dd->subdomain_lat_max = dd->subdomain_lat_min
10126 + (lat_range) / (double) ctl->dd_subdomains_meridional;
10127 }
10128
10129 LOG(2, "Total longitude range: %g deg", lon_range);
10130 LOG(2, "Total latitude range: %g deg", lat_range);
10131
10132 LOG(2, "Define subdomain properties.");
10133 LOG(2, "MPI information: Rank %d, Size %d", dd->rank, dd->size);
10134 LOG(2, "Edge position: l=%d,r=%d,t=%d, b=%d", (int) left, (int) right,
10135 (int) top, (int) bottom);
10136 LOG(2, "Sizes for limits: EX %d EY %d EP %d", EX, EY, EP);
10137 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d", met->nx,
10138 met->ny, met->np);
10139 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
10140 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
10141 (int) dd->halo_bnd_count[1]);
10142 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
10143 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
10144 (int) dd->subdomain_count[1]);
10145 LOG(2, "Subdomain start: nx %ld ny %ld np %ld", dd->subdomain_start[3],
10146 dd->subdomain_start[2], dd->subdomain_start[1]);
10147 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld", dd->halo_bnd_start[3],
10148 dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
10149 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
10150
10151 LOG(2, " %d Subdomain longitudes: %g, %g ... %g deg (edges: %g to %g)",
10152 dd->rank, met->lon[0], met->lon[1], met->lon[met->nx - 1],
10153 dd->subdomain_lon_min, dd->subdomain_lon_max);
10154 LOG(2, " %d Subdomain latitudes: %g, %g ... %g deg (edges: %g to %g)",
10155 dd->rank, met->lat[0], met->lat[1], met->lat[met->ny - 1],
10156 dd->subdomain_lat_min, dd->subdomain_lat_max);
10157
10158 free(help_lon_glob);
10159 free(help_lat_glob);
10160}
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3173
int rank
Rank of node.
Definition: mptrac.h:3620
double subdomain_lat_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3644
int size
Size of node.
Definition: mptrac.h:3623
double subdomain_lat_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3647

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

10166 {
10167
10168 /* Set timer... */
10169 SELECT_TIMER("READ_MET_PBL", "METPROC");
10170 LOG(2, "Calculate planetary boundary layer...");
10171
10172 /* Convert PBL height from meteo file to pressure... */
10173 if (ctl->met_pbl == 1) {
10174
10175 /* Loop over grid points... */
10176#pragma omp parallel for default(shared) collapse(2)
10177 for (int ix = 0; ix < met->nx; ix++)
10178 for (int iy = 0; iy < met->ny; iy++) {
10179
10180 /* Get pressure at top of PBL... */
10181 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
10182 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
10183 met->pbl[ix][iy] =
10184 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
10185 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
10186 }
10187 }
10188
10189 /* Determine PBL based on Richardson number... */
10190 else if (ctl->met_pbl == 2) {
10191
10192 /* Parameters used to estimate the height of the PBL
10193 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
10194 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
10195
10196 /* Loop over grid points... */
10197#pragma omp parallel for default(shared) collapse(2)
10198 for (int ix = 0; ix < met->nx; ix++)
10199 for (int iy = 0; iy < met->ny; iy++) {
10200
10201 /* Set bottom level of PBL... */
10202 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
10203
10204 /* Find lowest level near the bottom... */
10205 int ip;
10206 for (ip = 1; ip < met->np; ip++)
10207 if (met->p[ip] < pbl_bot)
10208 break;
10209
10210 /* Get near surface data... */
10211 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
10212 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
10213 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
10214
10215 /* Init... */
10216 double rib_old = 0;
10217
10218 /* Loop over levels... */
10219 for (; ip < met->np; ip++) {
10220
10221 /* Get squared horizontal wind speed... */
10222 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
10223 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
10224 vh2 = MAX(vh2, SQR(umin));
10225
10226 /* Calculate bulk Richardson number... */
10227 const double rib =
10228 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
10229 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
10230 met->h2o[ix][iy][ip]) - tvs) / vh2;
10231
10232 /* Check for critical value... */
10233 if (rib >= rib_crit) {
10234 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
10235 rib, met->p[ip], rib_crit));
10236 if (met->pbl[ix][iy] > pbl_bot)
10237 met->pbl[ix][iy] = (float) pbl_bot;
10238 break;
10239 }
10240
10241 /* Save Richardson number... */
10242 rib_old = rib;
10243 }
10244 }
10245 }
10246
10247 /* Determine PBL based on potential temperature... */
10248 if (ctl->met_pbl == 3) {
10249
10250 /* Parameters used to estimate the height of the PBL
10251 (following HYSPLIT model)... */
10252 const double dtheta = 2.0, zmin = 0.1;
10253
10254 /* Loop over grid points... */
10255#pragma omp parallel for default(shared) collapse(2)
10256 for (int ix = 0; ix < met->nx; ix++)
10257 for (int iy = 0; iy < met->ny; iy++) {
10258
10259 /* Potential temperature at the surface... */
10260 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
10261
10262 /* Find topmost level where theta exceeds surface value by 2 K... */
10263 int ip;
10264 for (ip = met->np - 2; ip > 0; ip--)
10265 if (met->p[ip] >= 300.)
10266 if (met->p[ip] > met->ps[ix][iy]
10267 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
10268 break;
10269
10270 /* Interpolate... */
10271 met->pbl[ix][iy]
10272 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
10273 met->p[ip + 1],
10274 THETA(met->p[ip], met->t[ix][iy][ip]),
10275 met->p[ip], theta0 + dtheta));
10276
10277 /* Check minimum value... */
10278 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
10279 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
10280 met->pbl[ix][iy] = (float) pbl_min;
10281 }
10282 }
10283
10284 /* Loop over grid points... */
10285#pragma omp parallel for default(shared) collapse(2)
10286 for (int ix = 0; ix < met->nx; ix++)
10287 for (int iy = 0; iy < met->ny; iy++) {
10288
10289 /* Check minimum value... */
10290 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
10291 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
10292
10293 /* Check maximum value... */
10294 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
10295 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
10296 }
10297}
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 10301 of file mptrac.c.

10302 {
10303
10304 /* Set timer... */
10305 SELECT_TIMER("READ_MET_PERIODIC", "METPROC");
10306 LOG(2, "Apply periodic boundary conditions...");
10307
10308 /* Check longitudes... */
10309 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
10310 + met->lon[1] - met->lon[0] - 360) < 0.01))
10311 return;
10312
10313 /* Increase longitude counter... */
10314 if ((++met->nx) >= EX)
10315 ERRMSG("Cannot create periodic boundary conditions!");
10316
10317 /* Set longitude... */
10318 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
10319
10320 /* Loop over latitudes and pressure levels... */
10321#pragma omp parallel for default(shared)
10322 for (int iy = 0; iy < met->ny; iy++) {
10323 met->ps[met->nx - 1][iy] = met->ps[0][iy];
10324 met->zs[met->nx - 1][iy] = met->zs[0][iy];
10325 met->ts[met->nx - 1][iy] = met->ts[0][iy];
10326 met->us[met->nx - 1][iy] = met->us[0][iy];
10327 met->vs[met->nx - 1][iy] = met->vs[0][iy];
10328 met->ess[met->nx - 1][iy] = met->ess[0][iy];
10329 met->nss[met->nx - 1][iy] = met->nss[0][iy];
10330 met->shf[met->nx - 1][iy] = met->shf[0][iy];
10331 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
10332 met->sst[met->nx - 1][iy] = met->sst[0][iy];
10333 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
10334 met->cape[met->nx - 1][iy] = met->cape[0][iy];
10335 met->cin[met->nx - 1][iy] = met->cin[0][iy];
10336 for (int ip = 0; ip < met->np; ip++) {
10337 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
10338 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
10339 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
10340 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
10341 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
10342 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
10343 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
10344 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
10345 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
10346 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
10347 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
10348 }
10349 for (int ip = 0; ip < met->npl; ip++) {
10350 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
10351 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
10352 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
10353 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
10354 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
10355 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
10356 }
10357 }
10358}

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

10363 {
10364
10365 /* Set timer... */
10366 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC");
10367 LOG(2, "Apply fix for polar winds...");
10368
10369 /* Check latitudes... */
10370 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
10371 return;
10372
10373 /* Loop over hemispheres... */
10374 for (int ihem = 0; ihem < 2; ihem++) {
10375
10376 /* Set latitude indices... */
10377 int i89 = 1, i90 = 0, sign = 1;
10378 if (ihem == 1) {
10379 i89 = met->ny - 2;
10380 i90 = met->ny - 1;
10381 }
10382 if (met->lat[i90] < 0)
10383 sign = -1;
10384
10385 /* Look-up table of cosinus and sinus... */
10386 double clon[EX], slon[EX];
10387#pragma omp parallel for default(shared)
10388 for (int ix = 0; ix < met->nx; ix++) {
10389 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
10390 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
10391 }
10392
10393 /* Loop over levels... */
10394#pragma omp parallel for default(shared)
10395 for (int ip = 0; ip < met->np; ip++) {
10396
10397 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
10398 double vel89x = 0, vel89y = 0;
10399 for (int ix = 0; ix < met->nx; ix++) {
10400 vel89x +=
10401 (met->u[ix][i89][ip] * clon[ix] -
10402 met->v[ix][i89][ip] * slon[ix]) / met->nx;
10403 vel89y +=
10404 (met->u[ix][i89][ip] * slon[ix] +
10405 met->v[ix][i89][ip] * clon[ix]) / met->nx;
10406 }
10407
10408 /* Replace 90 degree winds by 89 degree mean... */
10409 for (int ix = 0; ix < met->nx; ix++) {
10410 met->u[ix][i90][ip]
10411 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
10412 met->v[ix][i90][ip]
10413 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
10414 }
10415 }
10416 }
10417}

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

10422 {
10423
10424 double pows[EP];
10425
10426 /* Set timer... */
10427 SELECT_TIMER("READ_MET_PV", "METPROC");
10428 LOG(2, "Calculate potential vorticity...");
10429
10430 /* Set powers... */
10431#pragma omp parallel for default(shared)
10432 for (int ip = 0; ip < met->np; ip++)
10433 pows[ip] = pow(1000. / met->p[ip], 0.286);
10434
10435 /* Loop over grid points... */
10436#pragma omp parallel for default(shared)
10437 for (int ix = 0; ix < met->nx; ix++) {
10438
10439 /* Set indices... */
10440 const int ix0 = MAX(ix - 1, 0);
10441 const int ix1 = MIN(ix + 1, met->nx - 1);
10442
10443 /* Loop over grid points... */
10444 for (int iy = 0; iy < met->ny; iy++) {
10445
10446 /* Set indices... */
10447 const int iy0 = MAX(iy - 1, 0);
10448 const int iy1 = MIN(iy + 1, met->ny - 1);
10449
10450 /* Set auxiliary variables... */
10451 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
10452 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
10453 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
10454 const double c0 = cos(DEG2RAD(met->lat[iy0]));
10455 const double c1 = cos(DEG2RAD(met->lat[iy1]));
10456 const double cr = cos(DEG2RAD(latr));
10457 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
10458
10459 /* Loop over grid points... */
10460 for (int ip = 0; ip < met->np; ip++) {
10461
10462 /* Get gradients in longitude... */
10463 const double dtdx
10464 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
10465 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
10466
10467 /* Get gradients in latitude... */
10468 const double dtdy
10469 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
10470 const double dudy
10471 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
10472
10473 /* Set indices... */
10474 const int ip0 = MAX(ip - 1, 0);
10475 const int ip1 = MIN(ip + 1, met->np - 1);
10476
10477 /* Get gradients in pressure... */
10478 double dtdp, dudp, dvdp;
10479 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
10480 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
10481 if (ip != ip0 && ip != ip1) {
10482 double denom = dp0 * dp1 * (dp0 + dp1);
10483 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
10484 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
10485 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
10486 / denom;
10487 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
10488 - dp1 * dp1 * met->u[ix][iy][ip0]
10489 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
10490 / denom;
10491 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
10492 - dp1 * dp1 * met->v[ix][iy][ip0]
10493 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
10494 / denom;
10495 } else {
10496 const double denom = dp0 + dp1;
10497 dtdp =
10498 (met->t[ix][iy][ip1] * pows[ip1] -
10499 met->t[ix][iy][ip0] * pows[ip0]) / denom;
10500 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
10501 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
10502 }
10503
10504 /* Calculate PV... */
10505 met->pv[ix][iy][ip] = (float)
10506 (1e6 * G0 *
10507 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
10508 }
10509 }
10510 }
10511
10512 /* Fix for polar regions... */
10513#pragma omp parallel for default(shared)
10514 for (int ix = 0; ix < met->nx; ix++)
10515 for (int ip = 0; ip < met->np; ip++) {
10516 met->pv[ix][0][ip]
10517 = met->pv[ix][1][ip]
10518 = met->pv[ix][2][ip];
10519 met->pv[ix][met->ny - 1][ip]
10520 = met->pv[ix][met->ny - 2][ip]
10521 = met->pv[ix][met->ny - 3][ip];
10522 }
10523}
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:550
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:529

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

10528 {
10529
10530 /* Set timer... */
10531 SELECT_TIMER("READ_MET_OZONE", "METPROC");
10532 LOG(2, "Calculate total column ozone...");
10533
10534 /* Loop over columns... */
10535#pragma omp parallel for default(shared) collapse(2)
10536 for (int ix = 0; ix < met->nx; ix++)
10537 for (int iy = 0; iy < met->ny; iy++) {
10538
10539 /* Integrate... */
10540 double cd = 0;
10541 for (int ip = 1; ip < met->np; ip++)
10542 if (met->p[ip - 1] <= met->ps[ix][iy]) {
10543 const double vmr =
10544 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
10545 const double dp = met->p[ip - 1] - met->p[ip];
10546 cd += vmr * MO3 / MA * dp * 1e2 / G0;
10547 }
10548
10549 /* Convert to Dobson units... */
10550 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
10551 }
10552}

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

10558 {
10559
10560 met_t *help;
10561
10562 /* Check parameters... */
10563 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
10564 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
10565 return;
10566
10567 /* Set timer... */
10568 SELECT_TIMER("READ_MET_SAMPLE", "METPROC");
10569 LOG(2, "Downsampling of meteo data...");
10570
10571 /* Allocate... */
10572 ALLOC(help, met_t, 1);
10573
10574 /* Copy data... */
10575 help->nx = met->nx;
10576 help->ny = met->ny;
10577 help->np = met->np;
10578 memcpy(help->lon, met->lon, sizeof(met->lon));
10579 memcpy(help->lat, met->lat, sizeof(met->lat));
10580 memcpy(help->p, met->p, sizeof(met->p));
10581
10582 /* Smoothing... */
10583 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
10584 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
10585 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
10586 help->ps[ix][iy] = 0;
10587 help->zs[ix][iy] = 0;
10588 help->ts[ix][iy] = 0;
10589 help->us[ix][iy] = 0;
10590 help->vs[ix][iy] = 0;
10591 help->ess[ix][iy] = 0;
10592 help->nss[ix][iy] = 0;
10593 help->shf[ix][iy] = 0;
10594 help->lsm[ix][iy] = 0;
10595 help->sst[ix][iy] = 0;
10596 help->pbl[ix][iy] = 0;
10597 help->cape[ix][iy] = 0;
10598 help->cin[ix][iy] = 0;
10599 help->t[ix][iy][ip] = 0;
10600 help->u[ix][iy][ip] = 0;
10601 help->v[ix][iy][ip] = 0;
10602 help->w[ix][iy][ip] = 0;
10603 help->h2o[ix][iy][ip] = 0;
10604 help->o3[ix][iy][ip] = 0;
10605 help->lwc[ix][iy][ip] = 0;
10606 help->rwc[ix][iy][ip] = 0;
10607 help->iwc[ix][iy][ip] = 0;
10608 help->swc[ix][iy][ip] = 0;
10609 help->cc[ix][iy][ip] = 0;
10610 float wsum = 0;
10611 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
10612 ix2++) {
10613 int ix3 = ix2;
10614 if (ix3 < 0)
10615 ix3 += met->nx;
10616 else if (ix3 >= met->nx)
10617 ix3 -= met->nx;
10618
10619 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
10620 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
10621 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
10622 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
10623 const float w =
10624 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
10625 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
10626 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
10627 help->ps[ix][iy] += w * met->ps[ix3][iy2];
10628 help->zs[ix][iy] += w * met->zs[ix3][iy2];
10629 help->ts[ix][iy] += w * met->ts[ix3][iy2];
10630 help->us[ix][iy] += w * met->us[ix3][iy2];
10631 help->vs[ix][iy] += w * met->vs[ix3][iy2];
10632 help->ess[ix][iy] += w * met->ess[ix3][iy2];
10633 help->nss[ix][iy] += w * met->nss[ix3][iy2];
10634 help->shf[ix][iy] += w * met->shf[ix3][iy2];
10635 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
10636 help->sst[ix][iy] += w * met->sst[ix3][iy2];
10637 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
10638 help->cape[ix][iy] += w * met->cape[ix3][iy2];
10639 help->cin[ix][iy] += w * met->cin[ix3][iy2];
10640 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
10641 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
10642 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
10643 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
10644 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
10645 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
10646 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
10647 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
10648 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
10649 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
10650 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
10651 wsum += w;
10652 }
10653 }
10654 help->ps[ix][iy] /= wsum;
10655 help->zs[ix][iy] /= wsum;
10656 help->ts[ix][iy] /= wsum;
10657 help->us[ix][iy] /= wsum;
10658 help->vs[ix][iy] /= wsum;
10659 help->ess[ix][iy] /= wsum;
10660 help->nss[ix][iy] /= wsum;
10661 help->shf[ix][iy] /= wsum;
10662 help->lsm[ix][iy] /= wsum;
10663 help->sst[ix][iy] /= wsum;
10664 help->pbl[ix][iy] /= wsum;
10665 help->cape[ix][iy] /= wsum;
10666 help->cin[ix][iy] /= wsum;
10667 help->t[ix][iy][ip] /= wsum;
10668 help->u[ix][iy][ip] /= wsum;
10669 help->v[ix][iy][ip] /= wsum;
10670 help->w[ix][iy][ip] /= wsum;
10671 help->h2o[ix][iy][ip] /= wsum;
10672 help->o3[ix][iy][ip] /= wsum;
10673 help->lwc[ix][iy][ip] /= wsum;
10674 help->rwc[ix][iy][ip] /= wsum;
10675 help->iwc[ix][iy][ip] /= wsum;
10676 help->swc[ix][iy][ip] /= wsum;
10677 help->cc[ix][iy][ip] /= wsum;
10678 }
10679 }
10680 }
10681
10682 /* Downsampling... */
10683 met->nx = 0;
10684 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
10685 met->lon[met->nx] = help->lon[ix];
10686 met->ny = 0;
10687 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
10688 met->lat[met->ny] = help->lat[iy];
10689 met->ps[met->nx][met->ny] = help->ps[ix][iy];
10690 met->zs[met->nx][met->ny] = help->zs[ix][iy];
10691 met->ts[met->nx][met->ny] = help->ts[ix][iy];
10692 met->us[met->nx][met->ny] = help->us[ix][iy];
10693 met->vs[met->nx][met->ny] = help->vs[ix][iy];
10694 met->ess[met->nx][met->ny] = help->ess[ix][iy];
10695 met->nss[met->nx][met->ny] = help->nss[ix][iy];
10696 met->shf[met->nx][met->ny] = help->shf[ix][iy];
10697 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
10698 met->sst[met->nx][met->ny] = help->sst[ix][iy];
10699 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
10700 met->cape[met->nx][met->ny] = help->cape[ix][iy];
10701 met->cin[met->nx][met->ny] = help->cin[ix][iy];
10702 met->np = 0;
10703 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
10704 met->p[met->np] = help->p[ip];
10705 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
10706 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
10707 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
10708 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
10709 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
10710 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
10711 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
10712 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
10713 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
10714 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
10715 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
10716 met->np++;
10717 }
10718 met->ny++;
10719 }
10720 met->nx++;
10721 }
10722
10723 /* Free... */
10724 free(help);
10725}

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

10732 {
10733
10734 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
10735 th2[200], z[EP], z2[200];
10736
10737 /* Set timer... */
10738 SELECT_TIMER("READ_MET_TROPO", "METPROC");
10739 LOG(2, "Calculate tropopause...");
10740
10741 /* Get altitude and pressure profiles... */
10742#pragma omp parallel for default(shared)
10743 for (int iz = 0; iz < met->np; iz++)
10744 z[iz] = Z(met->p[iz]);
10745#pragma omp parallel for default(shared)
10746 for (int iz = 0; iz <= 190; iz++) {
10747 z2[iz] = 4.5 + 0.1 * iz;
10748 p2[iz] = P(z2[iz]);
10749 }
10750
10751 /* Do not calculate tropopause... */
10752 if (ctl->met_tropo == 0)
10753#pragma omp parallel for default(shared) collapse(2)
10754 for (int ix = 0; ix < met->nx; ix++)
10755 for (int iy = 0; iy < met->ny; iy++)
10756 met->pt[ix][iy] = NAN;
10757
10758 /* Use tropopause climatology... */
10759 else if (ctl->met_tropo == 1) {
10760#pragma omp parallel for default(shared) collapse(2)
10761 for (int ix = 0; ix < met->nx; ix++)
10762 for (int iy = 0; iy < met->ny; iy++)
10763 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
10764 }
10765
10766 /* Use cold point... */
10767 else if (ctl->met_tropo == 2) {
10768
10769 /* Loop over grid points... */
10770#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10771 for (int ix = 0; ix < met->nx; ix++)
10772 for (int iy = 0; iy < met->ny; iy++) {
10773
10774 /* Interpolate temperature profile... */
10775 for (int iz = 0; iz < met->np; iz++)
10776 t[iz] = met->t[ix][iy][iz];
10777 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
10778
10779 /* Find minimum... */
10780 int iz = (int) gsl_stats_min_index(t2, 1, 171);
10781 if (iz > 0 && iz < 170)
10782 met->pt[ix][iy] = (float) p2[iz];
10783 else
10784 met->pt[ix][iy] = NAN;
10785 }
10786 }
10787
10788 /* Use WMO definition... */
10789 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
10790
10791 /* Loop over grid points... */
10792#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10793 for (int ix = 0; ix < met->nx; ix++)
10794 for (int iy = 0; iy < met->ny; iy++) {
10795
10796 /* Interpolate temperature profile... */
10797 int iz;
10798 for (iz = 0; iz < met->np; iz++)
10799 t[iz] = met->t[ix][iy][iz];
10800 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
10801
10802 /* Find 1st tropopause... */
10803 met->pt[ix][iy] = NAN;
10804 for (iz = 0; iz <= 170; iz++) {
10805 int found = 1;
10806 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10807 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10808 found = 0;
10809 break;
10810 }
10811 if (found) {
10812 if (iz > 0 && iz < 170)
10813 met->pt[ix][iy] = (float) p2[iz];
10814 break;
10815 }
10816 }
10817
10818 /* Find 2nd tropopause... */
10819 if (ctl->met_tropo == 4) {
10820 met->pt[ix][iy] = NAN;
10821 for (; iz <= 170; iz++) {
10822 int found = 1;
10823 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
10824 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
10825 found = 0;
10826 break;
10827 }
10828 if (found)
10829 break;
10830 }
10831 for (; iz <= 170; iz++) {
10832 int found = 1;
10833 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10834 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10835 found = 0;
10836 break;
10837 }
10838 if (found) {
10839 if (iz > 0 && iz < 170)
10840 met->pt[ix][iy] = (float) p2[iz];
10841 break;
10842 }
10843 }
10844 }
10845 }
10846 }
10847
10848 /* Use dynamical tropopause... */
10849 else if (ctl->met_tropo == 5) {
10850
10851 /* Loop over grid points... */
10852#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
10853 for (int ix = 0; ix < met->nx; ix++)
10854 for (int iy = 0; iy < met->ny; iy++) {
10855
10856 /* Interpolate potential vorticity profile... */
10857 for (int iz = 0; iz < met->np; iz++)
10858 pv[iz] = met->pv[ix][iy][iz];
10859 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
10860
10861 /* Interpolate potential temperature profile... */
10862 for (int iz = 0; iz < met->np; iz++)
10863 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
10864 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
10865
10866 /* Find dynamical tropopause... */
10867 met->pt[ix][iy] = NAN;
10868 for (int iz = 0; iz <= 170; iz++)
10869 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
10870 || th2[iz] >= ctl->met_tropo_theta) {
10871 if (iz > 0 && iz < 170)
10872 met->pt[ix][iy] = (float) p2[iz];
10873 break;
10874 }
10875 }
10876 }
10877
10878 else
10879 ERRMSG("Cannot calculate tropopause!");
10880
10881 /* Interpolate temperature, geopotential height, and water vapor... */
10882#pragma omp parallel for default(shared) collapse(2)
10883 for (int ix = 0; ix < met->nx; ix++)
10884 for (int iy = 0; iy < met->ny; iy++) {
10885 double h2ot, tt, zt;
10887 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
10888 met->lat[iy], &tt, ci, cw, 1);
10889 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
10890 met->lat[iy], &zt, ci, cw, 0);
10891 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
10892 met->lat[iy], &h2ot, ci, cw, 0);
10893 met->tt[ix][iy] = (float) tt;
10894 met->zt[ix][iy] = (float) zt;
10895 met->h2ot[ix][iy] = (float) h2ot;
10896 }
10897}
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:11107
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:991
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 10901 of file mptrac.c.

10909 {
10910
10911 /* Write info... */
10912 LOG(1, "Read observation data: %s", filename);
10913
10914 /* Read data... */
10915 if (ctl->obs_type == 0)
10916 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
10917 else if (ctl->obs_type == 1)
10918 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
10919 else
10920 ERRMSG("Set OBS_TYPE to 0 or 1!");
10921
10922 /* Check time... */
10923 for (int i = 1; i < *nobs; i++)
10924 if (rt[i] < rt[i - 1])
10925 ERRMSG("Time must be ascending!");
10926
10927 /* Write info... */
10928 int n = *nobs;
10929 double mini, maxi;
10930 LOG(2, "Number of observations: %d", *nobs);
10931 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
10932 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
10933 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
10934 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
10935 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
10936 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
10937 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
10938 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
10939 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
10940 LOG(2, "Observation range: %g ... %g", mini, maxi);
10941}
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:10945
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:10973
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 10945 of file mptrac.c.

10952 {
10953
10954 /* Open observation data file... */
10955 FILE *in;
10956 if (!(in = fopen(filename, "r")))
10957 ERRMSG("Cannot open file!");
10958
10959 /* Read observations... */
10960 char line[LEN];
10961 while (fgets(line, LEN, in))
10962 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
10963 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
10964 if ((++(*nobs)) >= NOBS)
10965 ERRMSG("Too many observations!");
10966
10967 /* Close observation data file... */
10968 fclose(in);
10969}
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:328

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

10980 {
10981
10982 int ncid, varid;
10983
10984 /* Open netCDF file... */
10985 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
10986 ERRMSG("Cannot open file!");
10987
10988 /* Read the observations from the NetCDF file... */
10989 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
10990 NC_GET_DOUBLE("time", rt, 1);
10991 NC_GET_DOUBLE("alt", rz, 1);
10992 NC_GET_DOUBLE("lon", rlon, 1);
10993 NC_GET_DOUBLE("lat", rlat, 1);
10994 NC_GET_DOUBLE("obs", robs, 1);
10995
10996 /* Close file... */
10997 NC(nc_close(ncid));
10998}

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

11009 {
11010
11011 FILE *in = NULL;
11012
11013 char fullname1[LEN], fullname2[LEN], rval[LEN];
11014
11015 int contain = 0, i;
11016
11017 /* Open file... */
11018 if (filename[strlen(filename) - 1] != '-')
11019 if (!(in = fopen(filename, "r")))
11020 ERRMSG("Cannot open file!");
11021
11022 /* Set full variable name... */
11023 if (arridx >= 0) {
11024 sprintf(fullname1, "%s[%d]", varname, arridx);
11025 sprintf(fullname2, "%s[*]", varname);
11026 } else {
11027 sprintf(fullname1, "%s", varname);
11028 sprintf(fullname2, "%s", varname);
11029 }
11030
11031 /* Read data... */
11032 if (in != NULL) {
11033 char dummy[LEN], line[LEN], rvarname[LEN];
11034 while (fgets(line, LEN, in)) {
11035 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
11036 if (strcasecmp(rvarname, fullname1) == 0 ||
11037 strcasecmp(rvarname, fullname2) == 0) {
11038 contain = 1;
11039 break;
11040 }
11041 }
11042 }
11043 for (i = 1; i < argc - 1; i++)
11044 if (strcasecmp(argv[i], fullname1) == 0 ||
11045 strcasecmp(argv[i], fullname2) == 0) {
11046 sprintf(rval, "%s", argv[i + 1]);
11047 contain = 1;
11048 break;
11049 }
11050
11051 /* Close file... */
11052 if (in != NULL)
11053 fclose(in);
11054
11055 /* Check for missing variables... */
11056 if (!contain) {
11057 if (strlen(defvalue) > 0)
11058 sprintf(rval, "%s", defvalue);
11059 else
11060 ERRMSG("Missing variable %s!\n", fullname1);
11061 }
11062
11063 /* Write info... */
11064 LOG(1, "%s = %s", fullname1, rval);
11065
11066 /* Return values... */
11067 if (value != NULL)
11068 sprintf(value, "%s", rval);
11069 return atof(rval);
11070}

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

11078 {
11079
11080 /* Convert particle radius from microns to m... */
11081 const double rp_help = rp * 1e-6;
11082
11083 /* Density of dry air [kg / m^3]... */
11084 const double rho = RHO(p, T);
11085
11086 /* Dynamic viscosity of air [kg / (m s)]... */
11087 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
11088
11089 /* Thermal velocity of an air molecule [m / s]... */
11090 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
11091
11092 /* Mean free path of an air molecule [m]... */
11093 const double lambda = 2. * eta / (rho * v);
11094
11095 /* Knudsen number for air (dimensionless)... */
11096 const double K = lambda / rp_help;
11097
11098 /* Cunningham slip-flow correction (dimensionless)... */
11099 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
11100
11101 /* Sedimentation velocity [m / s]... */
11102 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
11103}
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:234

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

11114 {
11115
11116 /* Cubic spline interpolation... */
11117 if (method == 1) {
11118
11119 /* Allocate... */
11120 gsl_interp_accel *acc = gsl_interp_accel_alloc();
11121 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
11122
11123 /* Interpolate profile... */
11124 gsl_spline_init(s, x, y, (size_t) n);
11125 for (int i = 0; i < n2; i++)
11126 if (x2[i] <= x[0])
11127 y2[i] = y[0];
11128 else if (x2[i] >= x[n - 1])
11129 y2[i] = y[n - 1];
11130 else
11131 y2[i] = gsl_spline_eval(s, x2[i], acc);
11132
11133 /* Free... */
11134 gsl_spline_free(s);
11135 gsl_interp_accel_free(acc);
11136 }
11137
11138 /* Linear interpolation... */
11139 else {
11140 for (int i = 0; i < n2; i++)
11141 if (x2[i] <= x[0])
11142 y2[i] = y[0];
11143 else if (x2[i] >= x[n - 1])
11144 y2[i] = y[n - 1];
11145 else {
11146 const int idx = locate_irr(x, n, x2[i]);
11147 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
11148 }
11149 }
11150}
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 11154 of file mptrac.c.

11156 {
11157
11158 if (n <= 0)
11159 return 0;
11160
11161 float mean = 0, var = 0;
11162
11163 for (int i = 0; i < n; ++i) {
11164 mean += data[i];
11165 var += SQR(data[i]);
11166 }
11167
11168 var = var / (float) n - SQR(mean / (float) n);
11169
11170 return (var > 0 ? sqrtf(var) : 0);
11171}

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

11183 {
11184
11185 struct tm t0, t1;
11186
11187 t0.tm_year = 100;
11188 t0.tm_mon = 0;
11189 t0.tm_mday = 1;
11190 t0.tm_hour = 0;
11191 t0.tm_min = 0;
11192 t0.tm_sec = 0;
11193
11194 t1.tm_year = year - 1900;
11195 t1.tm_mon = mon - 1;
11196 t1.tm_mday = day;
11197 t1.tm_hour = hour;
11198 t1.tm_min = min;
11199 t1.tm_sec = sec;
11200
11201 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
11202}

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

11209 {
11210
11211 static char names[NTIMER][100], groups[NTIMER][100];
11212
11213 static double rt_name[NTIMER], rt_group[NTIMER],
11214 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
11215
11216 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
11217
11218 /* Get time... */
11219 t1 = omp_get_wtime();
11220 dt = t1 - t0;
11221
11222 /* Add elapsed time to current timers... */
11223 if (iname >= 0) {
11224 rt_name[iname] += dt;
11225 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
11226 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
11227 ct_name[iname]++;
11228 }
11229 if (igroup >= 0)
11230 rt_group[igroup] += t1 - t0;
11231
11232 /* Report timers... */
11233 if (output) {
11234 for (int i = 0; i < nname; i++)
11235 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
11236 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
11237 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
11238 for (int i = 0; i < ngroup; i++)
11239 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
11240 double total = 0.0;
11241 for (int i = 0; i < nname; i++)
11242 total += rt_name[i];
11243 LOG(1, "TIMER_TOTAL = %.3f s", total);
11244 }
11245
11246 /* Identify IDs of next timer... */
11247 for (iname = 0; iname < nname; iname++)
11248 if (strcasecmp(name, names[iname]) == 0)
11249 break;
11250 for (igroup = 0; igroup < ngroup; igroup++)
11251 if (strcasecmp(group, groups[igroup]) == 0)
11252 break;
11253
11254 /* Check whether this is a new timer... */
11255 if (iname >= nname) {
11256 sprintf(names[iname], "%s", name);
11257 if ((++nname) >= NTIMER)
11258 ERRMSG("Too many timers!");
11259 }
11260
11261 /* Check whether this is a new group... */
11262 if (igroup >= ngroup) {
11263 sprintf(groups[igroup], "%s", group);
11264 if ((++ngroup) >= NTIMER)
11265 ERRMSG("Too many groups!");
11266 }
11267
11268 /* Save starting time... */
11269 t0 = t1;
11270}
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2087

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

11276 {
11277
11278 char tstr[10];
11279
11280 double t;
11281
11282 /* Get time from filename... */
11283 int len = (int) strlen(filename);
11284 sprintf(tstr, "%.4s", &filename[len - offset]);
11285 int year = atoi(tstr);
11286 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
11287 int mon = atoi(tstr);
11288 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
11289 int day = atoi(tstr);
11290 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
11291 int hour = atoi(tstr);
11292 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
11293 int min = atoi(tstr);
11294
11295 /* Check time... */
11296 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
11297 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
11298 ERRMSG("Cannot read time from filename!");
11299
11300 /* Convert time to Julian seconds... */
11301 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
11302
11303 /* Return time... */
11304 return t;
11305}
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 11309 of file mptrac.c.

11312 {
11313
11314 /* Get tropopause pressure... */
11315 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
11316
11317 /* Get pressure range... */
11318 const double p1 = pt * 0.866877899;
11319 const double p0 = pt / 0.866877899;
11320
11321 /* Get weighting factor... */
11322 if (atm->p[ip] > p0)
11323 return 1;
11324 else if (atm->p[ip] < p1)
11325 return 0;
11326 else
11327 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
11328}
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 11332 of file mptrac.c.

11336 {
11337
11338 FILE *out;
11339
11340 /* Set time interval for output... */
11341 const double t0 = t - 0.5 * ctl->dt_mod;
11342 const double t1 = t + 0.5 * ctl->dt_mod;
11343
11344 /* Check if gnuplot output is requested... */
11345 if (ctl->atm_gpfile[0] != '-') {
11346
11347 /* Create gnuplot pipe... */
11348 if (!(out = popen("gnuplot", "w")))
11349 ERRMSG("Cannot create pipe to gnuplot!");
11350
11351 /* Set plot filename... */
11352 fprintf(out, "set out \"%s.png\"\n", filename);
11353
11354 /* Set time string... */
11355 double r;
11356 int year, mon, day, hour, min, sec;
11357 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11358 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
11359 year, mon, day, hour, min);
11360
11361 /* Dump gnuplot file to pipe... */
11362 FILE *in;
11363 if (!(in = fopen(ctl->atm_gpfile, "r")))
11364 ERRMSG("Cannot open file!");
11365 char line[LEN];
11366 while (fgets(line, LEN, in))
11367 fprintf(out, "%s", line);
11368 fclose(in);
11369 }
11370
11371 else {
11372
11373 /* Create file... */
11374 if (!(out = fopen(filename, "w")))
11375 ERRMSG("Cannot create file!");
11376 }
11377
11378 /* Write header... */
11379 fprintf(out,
11380 "# $1 = time [s]\n"
11381 "# $2 = altitude [km]\n"
11382 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11383 for (int iq = 0; iq < ctl->nq; iq++)
11384 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
11385 ctl->qnt_unit[iq]);
11386 fprintf(out, "\n");
11387
11388 /* Write data... */
11389 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
11390
11391 /* Check time... */
11392 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11393 continue;
11394
11395 /* Write output... */
11396 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
11397 atm->lon[ip], atm->lat[ip]);
11398 for (int iq = 0; iq < ctl->nq; iq++) {
11399 fprintf(out, " ");
11400 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11401 fprintf(out, ctl->qnt_format[iq], NAN);
11402 else
11403 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11404 }
11405 fprintf(out, "\n");
11406 }
11407
11408 /* Close file... */
11409 fclose(out);
11410}
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 11414 of file mptrac.c.

11417 {
11418
11419 FILE *out;
11420
11421 /* Create file... */
11422 if (!(out = fopen(filename, "w")))
11423 ERRMSG("Cannot create file!");
11424
11425 /* Write version of binary data... */
11426 int version = 100;
11427 FWRITE(&version, int,
11428 1,
11429 out);
11430
11431 /* Write data... */
11432 FWRITE(&atm->np, int,
11433 1,
11434 out);
11435 FWRITE(atm->time, double,
11436 (size_t) atm->np,
11437 out);
11438 FWRITE(atm->p, double,
11439 (size_t) atm->np,
11440 out);
11441 FWRITE(atm->lon, double,
11442 (size_t) atm->np,
11443 out);
11444 FWRITE(atm->lat, double,
11445 (size_t) atm->np,
11446 out);
11447 for (int iq = 0; iq < ctl->nq; iq++)
11448 FWRITE(atm->q[iq], double,
11449 (size_t) atm->np,
11450 out);
11451
11452 /* Write final flag... */
11453 int final = 999;
11454 FWRITE(&final, int,
11455 1,
11456 out);
11457
11458 /* Close file... */
11459 fclose(out);
11460}

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

11467 {
11468
11469 int tid, pid, ncid, varid;
11470 size_t start[2], count[2];
11471
11472 /* Create file... */
11473 NC(nc_create(filename, NC_NETCDF4, &ncid));
11474
11475 /* Define dimensions... */
11476 NC(nc_def_dim(ncid, "time", 1, &tid));
11477 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11478
11479 /* Define variables and their attributes... */
11480 int dim_ids[2] = { tid, pid };
11481 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11482 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11483 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11484 ctl->atm_nc_level, 0);
11485 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11486 ctl->atm_nc_level, 0);
11487 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11488 ctl->atm_nc_level, 0);
11489 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11490 for (int iq = 0; iq < ctl->nq; iq++)
11491 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11492 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11493 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11494
11495 /* Define global attributes... */
11496 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11497 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11498
11499 /* End definitions... */
11500 NC(nc_enddef(ncid));
11501
11502 /* Write data... */
11503 NC_PUT_DOUBLE("time", atm->time, 0);
11504 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11505 NC_PUT_DOUBLE("LON", atm->lon, 0);
11506 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11507 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11508 for (int iq = 0; iq < ctl->nq; iq++)
11509 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11510
11511 /* Close file... */
11512 NC(nc_close(ncid));
11513}
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1366
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1196
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1280

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

11521 {
11522
11523 /* Global Counter... */
11524 static size_t out_cnt = 0;
11525
11526 double r, r_start, r_stop;
11527 int year, mon, day, hour, min, sec;
11528 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
11529 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
11530 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
11531
11532 int ncid, varid, tid, pid, cid;
11533 int dim_ids[2];
11534
11535 /* time, nparc */
11536 size_t start[2];
11537 size_t count[2];
11538
11539 /* Determine start and stop times of calculation... */
11540 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11541 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
11542 &min_start, &sec_start, &r_start);
11543 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
11544 &min_stop, &sec_stop, &r_stop);
11545
11546 sprintf(filename_out,
11547 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
11548 year_start % 100, mon_start, day_start, hour_start,
11549 year_stop % 100, mon_stop, day_stop, hour_stop);
11550 LOG(1, "Write traj file: %s", filename_out);
11551
11552 /* Define hyperslap for the traj_file... */
11553 start[0] = out_cnt;
11554 start[1] = 0;
11555 count[0] = 1;
11556 count[1] = (size_t) atm->np;
11557
11558 /* Create the file at the first timestep... */
11559 if (out_cnt == 0) {
11560
11561 /* Create file... */
11562 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
11563
11564 /* Define dimensions... */
11565 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
11566 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11567 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
11568 dim_ids[0] = tid;
11569 dim_ids[1] = pid;
11570
11571 /* Define variables and their attributes... */
11572 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11573 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11574 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
11575 ctl->atm_nc_level, 0);
11576 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
11577 ctl->atm_nc_level, 0);
11578 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
11579 ctl->atm_nc_level, 0);
11580 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
11581 ctl->atm_nc_level, 0);
11582 for (int iq = 0; iq < ctl->nq; iq++)
11583 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11584 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11585 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11586
11587 /* Define global attributes... */
11588 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11589 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11590
11591 /* End definitions... */
11592 NC(nc_enddef(ncid));
11593 NC(nc_close(ncid));
11594 }
11595
11596 /* Increment global counter to change hyperslap... */
11597 out_cnt++;
11598
11599 /* Open file... */
11600 NC(nc_open(filename_out, NC_WRITE, &ncid));
11601
11602 /* Write data... */
11603 NC_PUT_DOUBLE("time", atm->time, 1);
11604 NC_PUT_DOUBLE("LAT", atm->lat, 1);
11605 NC_PUT_DOUBLE("LON", atm->lon, 1);
11606 NC_PUT_DOUBLE("PRESS", atm->p, 1);
11607 if (ctl->advect_vert_coord == 1) {
11608 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
11609 } else if (ctl->qnt_zeta >= 0) {
11610 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
11611 }
11612 for (int iq = 0; iq < ctl->nq; iq++)
11613 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
11614
11615 /* Close file... */
11616 NC(nc_close(ncid));
11617
11618 /* At the last time step create the init_fix_YYYYMMDDHH file... */
11619 if ((year == year_stop) && (mon == mon_stop)
11620 && (day == day_stop) && (hour == hour_stop)) {
11621
11622 /* Set filename... */
11623 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
11624 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
11625 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
11626 LOG(1, "Write init file: %s", filename_init);
11627
11628 /* Create file... */
11629 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
11630
11631 /* Define dimensions... */
11632 NC(nc_def_dim(ncid, "time", 1, &tid));
11633 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11634 dim_ids[0] = tid;
11635 dim_ids[1] = pid;
11636
11637 /* Define variables and their attributes... */
11638 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11639 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11640 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11641 ctl->atm_nc_level, 0);
11642 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11643 ctl->atm_nc_level, 0);
11644 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11645 ctl->atm_nc_level, 0);
11646 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11647 for (int iq = 0; iq < ctl->nq; iq++)
11648 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11649 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11650 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11651
11652 /* Define global attributes... */
11653 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11654 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11655
11656 /* End definitions... */
11657 NC(nc_enddef(ncid));
11658
11659 /* Write data... */
11660 NC_PUT_DOUBLE("time", atm->time, 0);
11661 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11662 NC_PUT_DOUBLE("LON", atm->lon, 0);
11663 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11664 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11665 for (int iq = 0; iq < ctl->nq; iq++)
11666 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11667
11668 /* Close file... */
11669 NC(nc_close(ncid));
11670 }
11671}
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 11675 of file mptrac.c.

11678 {
11679
11680 int ncid, obsid, varid;
11681
11682 size_t start[2], count[2];
11683
11684 /* Create file... */
11685 NC(nc_create(filename, NC_NETCDF4, &ncid));
11686
11687 /* Define dimensions... */
11688 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
11689
11690 /* Define variables and their attributes... */
11691 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
11692 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11693 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
11694 ctl->atm_nc_level, 0);
11695 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
11696 ctl->atm_nc_level, 0);
11697 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
11698 ctl->atm_nc_level, 0);
11699 for (int iq = 0; iq < ctl->nq; iq++)
11700 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
11701 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
11702 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11703
11704 /* Define global attributes... */
11705 NC_PUT_ATT_GLOBAL("featureType", "point");
11706
11707 /* End definitions... */
11708 NC(nc_enddef(ncid));
11709
11710 /* Write data... */
11711 NC_PUT_DOUBLE("time", atm->time, 0);
11712 NC_PUT_DOUBLE("press", atm->p, 0);
11713 NC_PUT_DOUBLE("lon", atm->lon, 0);
11714 NC_PUT_DOUBLE("lat", atm->lat, 0);
11715 for (int iq = 0; iq < ctl->nq; iq++)
11716 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11717
11718 /* Close file... */
11719 NC(nc_close(ncid));
11720}

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

11728 {
11729
11730 static FILE *out;
11731
11732 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
11733 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
11734
11735 static int *obscount, nobs, nk;
11736
11737 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
11738
11739 const int ensemble = (ctl->nens > 0);
11740
11741 /* Set timer */
11742 SELECT_TIMER("WRITE_CSI", "OUTPUT");
11743
11744 /* Check quantities... */
11745 if (ctl->qnt_m < 0)
11746 ERRMSG("Need quantity mass!");
11747 if (ensemble) {
11748 if (ctl->qnt_ens < 0)
11749 ERRMSG("Missing ensemble IDs!");
11750 if (ctl->nens > NENS)
11751 ERRMSG("Too many ensembles!");
11752 }
11753
11754 /* Init... */
11755 if (t == ctl->t_start) {
11756
11757 /* Allocate.. */
11758 ALLOC(area, double,
11759 ctl->csi_ny);
11760 ALLOC(rt, double,
11761 NOBS);
11762 ALLOC(rz, double,
11763 NOBS);
11764 ALLOC(rlon, double,
11765 NOBS);
11766 ALLOC(rlat, double,
11767 NOBS);
11768 ALLOC(robs, double,
11769 NOBS);
11770
11771 /* Read observation data... */
11772 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11773
11774 /* Read kernel data... */
11775 if (ctl->csi_kernel[0] != '-')
11776 read_kernel(ctl->csi_kernel, kz, kw, &nk);
11777
11778 /* Create new file... */
11779 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
11780 if (!(out = fopen(filename, "w")))
11781 ERRMSG("Cannot create file!");
11782
11783 /* Write header... */
11784 fprintf(out,
11785 "# $1 = time [s]\n"
11786 "# $2 = ensemble ID\n"
11787 "# $3 = number of hits (cx)\n"
11788 "# $4 = number of misses (cy)\n"
11789 "# $5 = number of false alarms (cz)\n"
11790 "# $6 = number of observations (cx + cy)\n"
11791 "# $7 = number of forecasts (cx + cz)\n"
11792 "# $8 = bias (%%)\n"
11793 "# $9 = POD (%%)\n"
11794 "# $10 = FAR (%%)\n"
11795 "# $11 = CSI (%%)\n"
11796 "# $12 = hits by random chance\n"
11797 "# $13 = ETS (%%)\n"
11798 "# $14 = Pearson R\n"
11799 "# $15 = Spearman R\n"
11800 "# $16 = mean error [kg/m²]\n"
11801 "# $17 = RMSE [kg/m²]\n"
11802 "# $18 = MAE [kg/m²]\n"
11803 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
11804
11805 /* Set grid box size... */
11806 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
11807 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
11808 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
11809
11810 /* Set horizontal coordinates... */
11811 for (int iy = 0; iy < ctl->csi_ny; iy++) {
11812 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
11813 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
11814 }
11815 }
11816
11817 /* Set time interval... */
11818 const double t0 = t - 0.5 * ctl->dt_mod;
11819 const double t1 = t + 0.5 * ctl->dt_mod;
11820
11821 /* Allocate... */
11822 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
11823 ALLOC(modmean, double,
11824 (ensemble ? ctl->nens : 1) * grid_size);
11825 ALLOC(obsmean, double,
11826 grid_size);
11827 ALLOC(obscount, int,
11828 grid_size);
11829 ALLOC(obsstd, double,
11830 grid_size);
11831
11832 /* Init... */
11833 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
11834 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
11835
11836 /* Loop over observations... */
11837 for (int i = 0; i < nobs; i++) {
11838 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
11839 continue;
11840
11841 /* Calculate indices... */
11842 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
11843 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
11844 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
11845 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11846 || iz >= ctl->csi_nz)
11847 continue;
11848
11849 /* Get mean observation index... */
11850 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11851 obsmean[idx] += robs[i];
11852 obsstd[idx] += SQR(robs[i]);
11853 obscount[idx]++;
11854 }
11855
11856 /* Analyze model data... */
11857 for (int ip = 0; ip < atm->np; ip++) {
11858
11859 /* Check time... */
11860 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11861 continue;
11862
11863 /* Get ensemble ID... */
11864 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
11865 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
11866 ERRMSG("Ensemble ID out of range!");
11867
11868 /* Get indices... */
11869 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
11870 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
11871 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
11872 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11873 || iz >= ctl->csi_nz)
11874 continue;
11875
11876 /* Get total mass in grid cell... */
11877 const int idx =
11878 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11879 modmean[idx] +=
11880 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11881 }
11882 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11883 /* Analyze all grid cells... */
11884 for (int ix = 0; ix < ctl->csi_nx; ix++)
11885 for (int iy = 0; iy < ctl->csi_ny; iy++)
11886 for (int iz = 0; iz < ctl->csi_nz; iz++) {
11887
11888 /* Calculate mean observation index... */
11889 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11890 if (e == 0)
11891 if (obscount[idx]) {
11892 obsmean[idx] /= obscount[idx];
11893 obsstd[idx] =
11894 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
11895 }
11896
11897 /* Calculate model mean per ensemble... */
11898 const int midx = e * grid_size + idx;
11899 if (modmean[midx] > 0)
11900 modmean[midx] /= (1e6 * area[iy]);
11901
11902 /* Check number of observations... */
11903 if (obscount[idx]) {
11904
11905 /* Calculate CSI... */
11906 ct[e]++;
11907 if (obsmean[idx] >= ctl->csi_obsmin
11908 && modmean[midx] >= ctl->csi_modmin)
11909 cx[e]++;
11910 else if (obsmean[idx] >= ctl->csi_obsmin)
11911 cy[e]++;
11912 else if (modmean[midx] >= ctl->csi_modmin)
11913 cz[e]++;
11914
11915 /* Save data for other verification statistics... */
11916 if (obsmean[idx] >= ctl->csi_obsmin
11917 || modmean[midx] >= ctl->csi_modmin) {
11918 x[n[e]] = modmean[midx];
11919 y[n[e]] = obsmean[idx];
11920 if (modmean[midx] >= ctl->csi_modmin)
11921 obsstdn[n[e]] = obsstd[idx];
11922 if ((++n[e]) >= NCSI)
11923 ERRMSG("Too many points for statistics!");
11924 }
11925 }
11926 }
11927 /* Write output... */
11928 if (fmod(t, ctl->csi_dt_out) == 0) {
11929
11930 if (n[e] == 0)
11931 continue;
11932
11933 /* Calculate verification statistics
11934 (https://www.cawcr.gov.au/projects/verification/) ... */
11935 static double work[2 * NCSI], work2[2 * NCSI];
11936 const int n_obs = cx[e] + cy[e];
11937 const int n_for = cx[e] + cz[e];
11938 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
11939 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
11940 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
11941 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
11942 const double csi =
11943 (cx[e] + cy[e] + cz[e] >
11944 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
11945 const double ets =
11946 (cx[e] + cy[e] + cz[e] - cx_rd >
11947 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
11948 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
11949 const double rho_s =
11950 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
11951 for (int i = 0; i < n[e]; i++) {
11952 work[i] = x[i] - y[i];
11953 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
11954 }
11955 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
11956 const double rmse =
11957 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
11958 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
11959 const double loglikelihood =
11960 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
11961
11962 /* Write... */
11963 fprintf(out,
11964 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
11965 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
11966 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
11967 loglikelihood, n[e]);
11968
11969 /* Set counters to zero... */
11970 for (int i = 0; i < n[e]; i++)
11971 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
11972 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
11973 }
11974 }
11975 /* Free... */
11976 free(modmean);
11977 free(obsmean);
11978 free(obscount);
11979 free(obsstd);
11980
11981 /* Finalize... */
11982 if (t == ctl->t_stop) {
11983
11984 /* Close output file... */
11985 fclose(out);
11986
11987 /* Free... */
11988 free(area);
11989 free(rt);
11990 free(rz);
11991 free(rlon);
11992 free(rlat);
11993 free(robs);
11994 }
11995}
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:10901
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:7544
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:2603
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:323
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:318
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 11999 of file mptrac.c.

12003 {
12004
12005 static FILE *out;
12006
12007 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
12008 x[3], zm[NENS];
12009
12010 static int n[NENS];
12011
12012 /* Set timer... */
12013 SELECT_TIMER("WRITE_ENS", "OUTPUT");
12014
12015 /* Check quantities... */
12016 if (ctl->qnt_ens < 0)
12017 ERRMSG("Missing ensemble IDs!");
12018
12019 /* Set time interval... */
12020 const double t0 = t - 0.5 * ctl->dt_mod;
12021 const double t1 = t + 0.5 * ctl->dt_mod;
12022
12023 /* Init... */
12024 for (int i = 0; i < NENS; i++) {
12025 for (int iq = 0; iq < ctl->nq; iq++)
12026 qm[iq][i] = qs[iq][i] = 0;
12027 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
12028 n[i] = 0;
12029 }
12030
12031 /* Loop over air parcels... */
12032 for (int ip = 0; ip < atm->np; ip++) {
12033
12034 /* Check time... */
12035 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12036 continue;
12037
12038 /* Check ensemble ID... */
12039 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
12040 ERRMSG("Ensemble ID is out of range!");
12041
12042 /* Get means... */
12043 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
12044 for (int iq = 0; iq < ctl->nq; iq++) {
12045 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
12046 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
12047 }
12048 xm[ctl->qnt_ens][0] += x[0];
12049 xm[ctl->qnt_ens][1] += x[1];
12050 xm[ctl->qnt_ens][2] += x[2];
12051 zm[ctl->qnt_ens] += Z(atm->p[ip]);
12052 n[ctl->qnt_ens]++;
12053 }
12054
12055 /* Create file... */
12056 LOG(1, "Write ensemble data: %s", filename);
12057 if (!(out = fopen(filename, "w")))
12058 ERRMSG("Cannot create file!");
12059
12060 /* Write header... */
12061 fprintf(out,
12062 "# $1 = time [s]\n"
12063 "# $2 = altitude [km]\n"
12064 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12065 for (int iq = 0; iq < ctl->nq; iq++)
12066 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
12067 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12068 for (int iq = 0; iq < ctl->nq; iq++)
12069 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
12070 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12071 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
12072
12073 /* Write data... */
12074 for (int i = 0; i < NENS; i++)
12075 if (n[i] > 0) {
12076 cart2geo(xm[i], &dummy, &lon, &lat);
12077 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
12078 for (int iq = 0; iq < ctl->nq; iq++) {
12079 fprintf(out, " ");
12080 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
12081 }
12082 for (int iq = 0; iq < ctl->nq; iq++) {
12083 fprintf(out, " ");
12084 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
12085 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
12086 }
12087 fprintf(out, " %d\n", n[i]);
12088 }
12089
12090 /* Close file... */
12091 fclose(out);
12092}
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 12096 of file mptrac.c.

12102 {
12103
12104 static double kz[EP], kw[EP];
12105
12106 static int nk;
12107
12108 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
12109
12110 int *ixs, *iys, *izs, *np;
12111
12112 /* Set timer... */
12113 SELECT_TIMER("WRITE_GRID", "OUTPUT");
12114
12115 /* Write info... */
12116 LOG(1, "Write grid data: %s", filename);
12117
12118 /* Init... */
12119 if (t == ctl->t_start) {
12120
12121 /* Read kernel data... */
12122 if (ctl->grid_kernel[0] != '-')
12123 read_kernel(ctl->grid_kernel, kz, kw, &nk);
12124 }
12125
12126 /* Allocate... */
12127 ALLOC(cd, double,
12128 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12129 for (int iq = 0; iq < ctl->nq; iq++) {
12130 ALLOC(mean[iq], double,
12131 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12132 ALLOC(sigma[iq], double,
12133 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12134 }
12135 ALLOC(vmr_impl, double,
12136 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12137 ALLOC(z, double,
12138 ctl->grid_nz);
12139 ALLOC(lon, double,
12140 ctl->grid_nx);
12141 ALLOC(lat, double,
12142 ctl->grid_ny);
12143 ALLOC(area, double,
12144 ctl->grid_ny);
12145 ALLOC(press, double,
12146 ctl->grid_nz);
12147 ALLOC(np, int,
12148 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12149 ALLOC(ixs, int,
12150 atm->np);
12151 ALLOC(iys, int,
12152 atm->np);
12153 ALLOC(izs, int,
12154 atm->np);
12155
12156 /* Set grid box size... */
12157 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
12158 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
12159 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
12160
12161 /* Set vertical coordinates... */
12162#pragma omp parallel for default(shared)
12163 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12164 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
12165 press[iz] = P(z[iz]);
12166 }
12167
12168 /* Set horizontal coordinates... */
12169 for (int ix = 0; ix < ctl->grid_nx; ix++)
12170 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
12171#pragma omp parallel for default(shared)
12172 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12173 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
12174 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
12175 }
12176
12177 /* Set time interval for output... */
12178 const double t0 = t - 0.5 * ctl->dt_mod;
12179 const double t1 = t + 0.5 * ctl->dt_mod;
12180
12181 /* Get grid box indices... */
12182#pragma omp parallel for default(shared)
12183 for (int ip = 0; ip < atm->np; ip++) {
12184 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
12185 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
12186 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
12187 if (atm->time[ip] < t0 || atm->time[ip] > t1
12188 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
12189 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
12190 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
12191 izs[ip] = -1;
12192 }
12193
12194 /* Average data... */
12195 for (int ip = 0; ip < atm->np; ip++)
12196 if (izs[ip] >= 0) {
12197 const int idx =
12198 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
12199 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
12200 np[idx]++;
12201 for (int iq = 0; iq < ctl->nq; iq++) {
12202 mean[iq][idx] += kernel * atm->q[iq][ip];
12203 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
12204 }
12205 }
12206
12207 /* Calculate column density and volume mixing ratio... */
12208#pragma omp parallel for default(shared)
12209 for (int ix = 0; ix < ctl->grid_nx; ix++)
12210 for (int iy = 0; iy < ctl->grid_ny; iy++)
12211 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12212
12213 /* Get grid index... */
12214 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12215
12216 /* Calculate column density... */
12217 cd[idx] = NAN;
12218 if (ctl->qnt_m >= 0)
12219 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
12220
12221 /* Calculate volume mixing ratio (implicit)... */
12222 vmr_impl[idx] = NAN;
12223 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
12224 && met1 != NULL) {
12225 vmr_impl[idx] = 0;
12226 if (mean[ctl->qnt_m][idx] > 0) {
12227
12228 /* Get temperature... */
12229 double temp;
12231 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
12232 lon[ix], lat[iy], &temp, ci, cw, 1);
12233
12234 /* Calculate volume mixing ratio... */
12235 vmr_impl[idx] =
12236 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
12237 }
12238 }
12239
12240 /* Calculate mean... */
12241 if (np[idx] > 0)
12242 for (int iq = 0; iq < ctl->nq; iq++) {
12243 mean[iq][idx] /= np[idx];
12244 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
12245 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
12246 } else
12247 for (int iq = 0; iq < ctl->nq; iq++) {
12248 mean[iq][idx] = NAN;
12249 sigma[iq][idx] = NAN;
12250 }
12251 }
12252
12253 /* Write ASCII data... */
12254 if (ctl->grid_type == 0)
12255 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
12256 t, z, lon, lat, area, dz, np);
12257
12258 /* Write netCDF data... */
12259 else if (ctl->grid_type == 1)
12260 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
12261 t, z, lon, lat, area, dz, np);
12262
12263 /* Error message... */
12264 else
12265 ERRMSG("Grid data format GRID_TYPE unknown!");
12266
12267 /* Free... */
12268 free(cd);
12269 for (int iq = 0; iq < ctl->nq; iq++) {
12270 free(mean[iq]);
12271 free(sigma[iq]);
12272 }
12273 free(vmr_impl);
12274 free(z);
12275 free(lon);
12276 free(lat);
12277 free(area);
12278 free(press);
12279 free(np);
12280 free(ixs);
12281 free(iys);
12282 free(izs);
12283}
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:12287
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:12391
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 12287 of file mptrac.c.

12300 {
12301
12302 FILE *out;
12303
12304 /* Check if gnuplot output is requested... */
12305 if (ctl->grid_gpfile[0] != '-') {
12306
12307 /* Create gnuplot pipe... */
12308 if (!(out = popen("gnuplot", "w")))
12309 ERRMSG("Cannot create pipe to gnuplot!");
12310
12311 /* Set plot filename... */
12312 fprintf(out, "set out \"%s.png\"\n", filename);
12313
12314 /* Set time string... */
12315 double r;
12316 int year, mon, day, hour, min, sec;
12317 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12318 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12319 year, mon, day, hour, min);
12320
12321 /* Dump gnuplot file to pipe... */
12322 FILE *in;
12323 char line[LEN];
12324 if (!(in = fopen(ctl->grid_gpfile, "r")))
12325 ERRMSG("Cannot open file!");
12326 while (fgets(line, LEN, in))
12327 fprintf(out, "%s", line);
12328 fclose(in);
12329 }
12330
12331 else {
12332
12333 /* Create file... */
12334 if (!(out = fopen(filename, "w")))
12335 ERRMSG("Cannot create file!");
12336 }
12337
12338 /* Write header... */
12339 fprintf(out,
12340 "# $1 = time [s]\n"
12341 "# $2 = altitude [km]\n"
12342 "# $3 = longitude [deg]\n"
12343 "# $4 = latitude [deg]\n"
12344 "# $5 = surface area [km^2]\n"
12345 "# $6 = layer depth [km]\n"
12346 "# $7 = column density (implicit) [kg/m^2]\n"
12347 "# $8 = volume mixing ratio (implicit) [ppv]\n"
12348 "# $9 = number of particles [1]\n");
12349 for (int iq = 0; iq < ctl->nq; iq++)
12350 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
12351 ctl->qnt_unit[iq]);
12352 if (ctl->grid_stddev)
12353 for (int iq = 0; iq < ctl->nq; iq++)
12354 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
12355 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12356 fprintf(out, "\n");
12357
12358 /* Write data... */
12359 for (int ix = 0; ix < ctl->grid_nx; ix++) {
12360 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
12361 fprintf(out, "\n");
12362 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12363 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
12364 fprintf(out, "\n");
12365 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12366 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12367 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
12368 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
12369 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
12370 for (int iq = 0; iq < ctl->nq; iq++) {
12371 fprintf(out, " ");
12372 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
12373 }
12374 if (ctl->grid_stddev)
12375 for (int iq = 0; iq < ctl->nq; iq++) {
12376 fprintf(out, " ");
12377 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
12378 }
12379 fprintf(out, "\n");
12380 }
12381 }
12382 }
12383 }
12384
12385 /* Close file... */
12386 fclose(out);
12387}
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 12391 of file mptrac.c.

12404 {
12405
12406 char longname[2 * LEN], varname[2 * LEN];
12407
12408 double *help;
12409
12410 int *help2, ncid, dimid[10], varid;
12411
12412 size_t start[2], count[2];
12413
12414 /* Allocate... */
12415 ALLOC(help, double,
12416 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12417 ALLOC(help2, int,
12418 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12419
12420 /* Create file... */
12421 NC(nc_create(filename, NC_NETCDF4, &ncid));
12422
12423 /* Define dimensions... */
12424 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
12425 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
12426 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
12427 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
12428 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
12429
12430 /* Define variables and their attributes... */
12431 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
12432 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12433 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
12434 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
12435 0);
12436 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
12437 0);
12438 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
12439 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
12440
12441 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
12442 ctl->grid_nc_level, 0);
12443 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
12444 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
12445 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
12446 for (int iq = 0; iq < ctl->nq; iq++) {
12447 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12448 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
12449 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12450 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12451 if (ctl->grid_stddev) {
12452 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12453 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
12454 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12455 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12456 }
12457 }
12458 /* End definitions... */
12459 NC(nc_enddef(ncid));
12460
12461 /* Write data... */
12462 NC_PUT_DOUBLE("time", &t, 0);
12463 NC_PUT_DOUBLE("lon", lon, 0);
12464 NC_PUT_DOUBLE("lat", lat, 0);
12465 NC_PUT_DOUBLE("z", z, 0);
12466 NC_PUT_DOUBLE("area", area, 0);
12467 NC_PUT_DOUBLE("dz", &dz, 0);
12468
12469 for (int ix = 0; ix < ctl->grid_nx; ix++)
12470 for (int iy = 0; iy < ctl->grid_ny; iy++)
12471 for (int iz = 0; iz < ctl->grid_nz; iz++)
12472 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12473 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12474 NC_PUT_DOUBLE("cd", help, 0);
12475
12476 for (int ix = 0; ix < ctl->grid_nx; ix++)
12477 for (int iy = 0; iy < ctl->grid_ny; iy++)
12478 for (int iz = 0; iz < ctl->grid_nz; iz++)
12479 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12480 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12481 NC_PUT_DOUBLE("vmr_impl", help, 0);
12482
12483 for (int ix = 0; ix < ctl->grid_nx; ix++)
12484 for (int iy = 0; iy < ctl->grid_ny; iy++)
12485 for (int iz = 0; iz < ctl->grid_nz; iz++)
12486 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12487 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12488 NC_PUT_INT("np", help2, 0);
12489
12490 for (int iq = 0; iq < ctl->nq; iq++) {
12491 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12492 for (int ix = 0; ix < ctl->grid_nx; ix++)
12493 for (int iy = 0; iy < ctl->grid_ny; iy++)
12494 for (int iz = 0; iz < ctl->grid_nz; iz++)
12495 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12496 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12497 NC_PUT_DOUBLE(varname, help, 0);
12498 }
12499
12500 if (ctl->grid_stddev)
12501 for (int iq = 0; iq < ctl->nq; iq++) {
12502 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12503 for (int ix = 0; ix < ctl->grid_nx; ix++)
12504 for (int iy = 0; iy < ctl->grid_ny; iy++)
12505 for (int iz = 0; iz < ctl->grid_nz; iz++)
12506 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12507 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12508 NC_PUT_DOUBLE(varname, help, 0);
12509 }
12510
12511 /* Close file... */
12512 NC(nc_close(ncid));
12513
12514 /* Free... */
12515 free(help);
12516 free(help2);
12517}
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1327

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

12524 {
12525
12526 /* Create file... */
12527 FILE *out;
12528 if (!(out = fopen(filename, "w")))
12529 ERRMSG("Cannot create file!");
12530
12531 /* Write type of binary data... */
12532 FWRITE(&ctl->met_type, int,
12533 1,
12534 out);
12535
12536 /* Write version of binary data... */
12537 int version = 103;
12538 FWRITE(&version, int,
12539 1,
12540 out);
12541
12542 /* Write grid data... */
12543 FWRITE(&met->time, double,
12544 1,
12545 out);
12546 FWRITE(&met->nx, int,
12547 1,
12548 out);
12549 FWRITE(&met->ny, int,
12550 1,
12551 out);
12552 FWRITE(&met->np, int,
12553 1,
12554 out);
12555 FWRITE(met->lon, double,
12556 (size_t) met->nx,
12557 out);
12558 FWRITE(met->lat, double,
12559 (size_t) met->ny,
12560 out);
12561 FWRITE(met->p, double,
12562 (size_t) met->np,
12563 out);
12564
12565 /* Write surface data... */
12566 write_met_bin_2d(out, met, met->ps, "PS");
12567 write_met_bin_2d(out, met, met->ts, "TS");
12568 write_met_bin_2d(out, met, met->zs, "ZS");
12569 write_met_bin_2d(out, met, met->us, "US");
12570 write_met_bin_2d(out, met, met->vs, "VS");
12571 write_met_bin_2d(out, met, met->ess, "ESS");
12572 write_met_bin_2d(out, met, met->nss, "NSS");
12573 write_met_bin_2d(out, met, met->shf, "SHF");
12574 write_met_bin_2d(out, met, met->lsm, "LSM");
12575 write_met_bin_2d(out, met, met->sst, "SST");
12576 write_met_bin_2d(out, met, met->pbl, "PBL");
12577 write_met_bin_2d(out, met, met->pt, "PT");
12578 write_met_bin_2d(out, met, met->tt, "TT");
12579 write_met_bin_2d(out, met, met->zt, "ZT");
12580 write_met_bin_2d(out, met, met->h2ot, "H2OT");
12581 write_met_bin_2d(out, met, met->pct, "PCT");
12582 write_met_bin_2d(out, met, met->pcb, "PCB");
12583 write_met_bin_2d(out, met, met->cl, "CL");
12584 write_met_bin_2d(out, met, met->plcl, "PLCL");
12585 write_met_bin_2d(out, met, met->plfc, "PLFC");
12586 write_met_bin_2d(out, met, met->pel, "PEL");
12587 write_met_bin_2d(out, met, met->cape, "CAPE");
12588 write_met_bin_2d(out, met, met->cin, "CIN");
12589 write_met_bin_2d(out, met, met->o3c, "O3C");
12590
12591 /* Write level data... */
12592 write_met_bin_3d(out, ctl, met, met->z, "Z",
12593 ctl->met_comp_prec[0], ctl->met_comp_tol[0]);
12594 write_met_bin_3d(out, ctl, met, met->t, "T",
12595 ctl->met_comp_prec[1], ctl->met_comp_tol[1]);
12596 write_met_bin_3d(out, ctl, met, met->u, "U",
12597 ctl->met_comp_prec[2], ctl->met_comp_tol[2]);
12598 write_met_bin_3d(out, ctl, met, met->v, "V",
12599 ctl->met_comp_prec[3], ctl->met_comp_tol[3]);
12600 write_met_bin_3d(out, ctl, met, met->w, "W",
12601 ctl->met_comp_prec[4], ctl->met_comp_tol[4]);
12602 write_met_bin_3d(out, ctl, met, met->pv, "PV",
12603 ctl->met_comp_prec[5], ctl->met_comp_tol[5]);
12604 write_met_bin_3d(out, ctl, met, met->h2o, "H2O",
12605 ctl->met_comp_prec[6], ctl->met_comp_tol[6]);
12606 write_met_bin_3d(out, ctl, met, met->o3, "O3",
12607 ctl->met_comp_prec[7], ctl->met_comp_tol[7]);
12608 write_met_bin_3d(out, ctl, met, met->lwc, "LWC",
12609 ctl->met_comp_prec[8], ctl->met_comp_tol[8]);
12610 write_met_bin_3d(out, ctl, met, met->rwc, "RWC",
12611 ctl->met_comp_prec[9], ctl->met_comp_tol[9]);
12612 write_met_bin_3d(out, ctl, met, met->iwc, "IWC",
12613 ctl->met_comp_prec[10], ctl->met_comp_tol[10]);
12614 write_met_bin_3d(out, ctl, met, met->swc, "SWC",
12615 ctl->met_comp_prec[11], ctl->met_comp_tol[11]);
12616 write_met_bin_3d(out, ctl, met, met->cc, "CC",
12617 ctl->met_comp_prec[12], ctl->met_comp_tol[12]);
12618 if (METVAR != 13)
12619 ERRMSG("Number of meteo variables doesn't match!");
12620
12621 /* Write final flag... */
12622 int final = 999;
12623 FWRITE(&final, int,
12624 1,
12625 out);
12626
12627 /* Close file... */
12628 fclose(out);
12629}
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:12662
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:12633
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 12633 of file mptrac.c.

12637 {
12638
12639 float *help;
12640
12641 /* Allocate... */
12642 ALLOC(help, float,
12643 EX * EY);
12644
12645 /* Copy data... */
12646 for (int ix = 0; ix < met->nx; ix++)
12647 for (int iy = 0; iy < met->ny; iy++)
12648 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
12649
12650 /* Write uncompressed data... */
12651 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
12652 FWRITE(help, float,
12653 (size_t) (met->nx * met->ny),
12654 out);
12655
12656 /* Free... */
12657 free(help);
12658}

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

12669 {
12670
12671 float *help;
12672
12673 /* Allocate... */
12674 ALLOC(help, float,
12675 EX * EY * EP);
12676
12677 /* Copy data... */
12678#pragma omp parallel for default(shared) collapse(2)
12679 for (int ix = 0; ix < met->nx; ix++)
12680 for (int iy = 0; iy < met->ny; iy++)
12681 for (int ip = 0; ip < met->np; ip++)
12682 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
12683
12684 /* Write uncompressed data... */
12685 if (ctl->met_type == 1) {
12686 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
12687 FWRITE(help, float,
12688 (size_t) (met->nx * met->ny * met->np),
12689 out);
12690 }
12691
12692 /* Write packed data... */
12693 else if (ctl->met_type == 2)
12694 compress_pck(varname, help, (size_t) (met->ny * met->nx),
12695 (size_t) met->np, 0, out);
12696
12697 /* Write ZFP data... */
12698#ifdef ZFP
12699 else if (ctl->met_type == 3) {
12700 FWRITE(&precision, int,
12701 1,
12702 out);
12703 FWRITE(&tolerance, double,
12704 1,
12705 out);
12706 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
12707 tolerance, 0, out);
12708 }
12709#endif
12710
12711 /* Write zstd data... */
12712#ifdef ZSTD
12713 else if (ctl->met_type == 4)
12714 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
12715 ctl->met_zstd_level, out);
12716#endif
12717
12718 /* Write cmultiscale data... */
12719#ifdef CMS
12720 else if (ctl->met_type == 5) {
12721 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
12722 (size_t) met->np, met->p, 0, out);
12723 }
12724#endif
12725
12726 /* Write SZ3 data... */
12727#ifdef SZ3
12728 else if (ctl->met_type == 7) {
12729 FWRITE(&precision, int,
12730 1,
12731 out);
12732 FWRITE(&tolerance, double,
12733 1,
12734 out);
12735 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
12736 tolerance, 0, out);
12737 }
12738#endif
12739
12740 /* Unknown method... */
12741 else {
12742 ERRMSG("MET_TYPE not supported!");
12743 LOG(3, "%d %g", precision, tolerance);
12744 }
12745
12746 /* Free... */
12747 free(help);
12748}
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 12752 of file mptrac.c.

12755 {
12756
12757 /* Create file... */
12758 int ncid, varid;
12759 size_t start[4], count[4];
12760 NC(nc_create(filename, NC_NETCDF4, &ncid));
12761
12762 /* Define dimensions... */
12763 int tid, lonid, latid, levid;
12764 NC(nc_def_dim(ncid, "time", 1, &tid));
12765 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
12766 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
12767 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
12768
12769 /* Define grid... */
12770 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
12771 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12772 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
12773 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
12774 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
12775
12776 /* Define surface variables... */
12777 int dimid2[2] = { latid, lonid };
12778 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
12779 ctl->met_nc_level, 0);
12780 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
12781 ctl->met_nc_level, 0);
12782 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
12783 ctl->met_nc_level, 0);
12784 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
12785 "m s**-1", ctl->met_nc_level, 0);
12786 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
12787 "m s**-1", ctl->met_nc_level, 0);
12788 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
12789 "Instantaneous eastward turbulent surface stress", "N m**-2",
12790 ctl->met_nc_level, 0);
12791 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
12792 "Instantaneous northward turbulent surface stress", "N m**-2",
12793 ctl->met_nc_level, 0);
12794 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
12795 "Instantaneous surface sensible heat flux", "W m**-1",
12796 ctl->met_nc_level, 0);
12797 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
12798 ctl->met_nc_level, 0);
12799 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
12800 ctl->met_nc_level, 0);
12801 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
12802 ctl->met_nc_level, 0);
12803 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
12804 ctl->met_nc_level, 0);
12805 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
12806 ctl->met_nc_level, 0);
12807 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
12808 ctl->met_nc_level, 0);
12809 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
12810 ctl->met_nc_level, 0);
12811 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
12812 ctl->met_nc_level, 0);
12813 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
12814 ctl->met_nc_level, 0);
12815 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
12816 "kg m**2", ctl->met_nc_level, 0);
12817 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
12818 "Pressure at lifted condensation level (LCL)", "Pa",
12819 ctl->met_nc_level, 0);
12820 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
12821 "Pressure at level of free convection (LFC)", "Pa",
12822 ctl->met_nc_level, 0);
12823 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
12824 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
12825 0);
12826 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
12827 "Convective available potential energy", "J kg**-1",
12828 ctl->met_nc_level, 0);
12829 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
12830 "J kg**-1", ctl->met_nc_level, 0);
12831 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
12832 ctl->met_nc_level, 0);
12833
12834 /* Define level data... */
12835 int dimid3[3] = { levid, latid, lonid };
12836 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
12837 ctl->met_nc_level, ctl->met_nc_quant);
12838 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
12839 ctl->met_nc_level, ctl->met_nc_quant);
12840 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
12841 ctl->met_nc_level, ctl->met_nc_quant);
12842 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
12843 ctl->met_nc_level, ctl->met_nc_quant);
12844 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
12845 ctl->met_nc_level, ctl->met_nc_quant);
12846 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
12847 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12848 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
12849 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12850 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
12851 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12852 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
12853 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12854 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
12855 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12856 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
12857 ctl->met_nc_level, ctl->met_nc_quant);
12858
12859 /* End definitions... */
12860 NC(nc_enddef(ncid));
12861
12862 /* Write grid data... */
12863 NC_PUT_DOUBLE("time", &met->time, 0);
12864 NC_PUT_DOUBLE("lon", met->lon, 0);
12865 NC_PUT_DOUBLE("lat", met->lat, 0);
12866 double phelp[EP];
12867 for (int ip = 0; ip < met->np; ip++)
12868 phelp[ip] = 100. * met->p[ip];
12869 NC_PUT_DOUBLE("lev", phelp, 0);
12870
12871 /* Write surface data... */
12872 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
12873 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
12874 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
12875 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
12876 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
12877 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
12878 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
12879 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
12880 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
12881 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
12882 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
12883 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
12884 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
12885 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
12886 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
12887 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
12888 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
12889 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
12890 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
12891 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
12892 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
12893 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
12894 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
12895 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
12896
12897 /* Write level data... */
12898 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
12899 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
12900 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
12901 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
12902 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
12903 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
12904 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
12905 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
12906 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
12907 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
12908 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
12909
12910 /* Close file... */
12911 NC(nc_close(ncid));
12912}
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:12916
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:12945
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2501
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2498
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 12916 of file mptrac.c.

12921 {
12922
12923 int varid;
12924 size_t start[4], count[4];
12925
12926 /* Allocate... */
12927 float *help;
12928 ALLOC(help, float,
12929 EX * EY);
12930
12931 /* Copy data... */
12932 for (int ix = 0; ix < met->nx; ix++)
12933 for (int iy = 0; iy < met->ny; iy++)
12934 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
12935
12936 /* Write data... */
12937 NC_PUT_FLOAT(varname, help, 0);
12938
12939 /* Free... */
12940 free(help);
12941}
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1304

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

12950 {
12951
12952 int varid;
12953 size_t start[4], count[4];
12954
12955 /* Allocate... */
12956 float *help;
12957 ALLOC(help, float,
12958 EX * EY * EP);
12959
12960 /* Copy data... */
12961 for (int ix = 0; ix < met->nx; ix++)
12962 for (int iy = 0; iy < met->ny; iy++)
12963 for (int ip = 0; ip < met->np; ip++)
12964 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
12965
12966 /* Write data... */
12967 NC_PUT_FLOAT(varname, help, 0);
12968
12969 /* Free... */
12970 free(help);
12971}

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

12981 {
12982
12983 static FILE *out;
12984
12985 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
12986 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
12987
12988 static int nobs, *obscount, ip, okay;
12989
12990 /* Set timer... */
12991 SELECT_TIMER("WRITE_PROF", "OUTPUT");
12992
12993 /* Init... */
12994 if (t == ctl->t_start) {
12995
12996 /* Check quantity index for mass... */
12997 if (ctl->qnt_m < 0)
12998 ERRMSG("Need quantity mass!");
12999
13000 /* Check molar mass... */
13001 if (ctl->molmass <= 0)
13002 ERRMSG("Specify molar mass!");
13003
13004 /* Allocate... */
13005 ALLOC(lon, double,
13006 ctl->prof_nx);
13007 ALLOC(lat, double,
13008 ctl->prof_ny);
13009 ALLOC(area, double,
13010 ctl->prof_ny);
13011 ALLOC(z, double,
13012 ctl->prof_nz);
13013 ALLOC(press, double,
13014 ctl->prof_nz);
13015 ALLOC(rt, double,
13016 NOBS);
13017 ALLOC(rz, double,
13018 NOBS);
13019 ALLOC(rlon, double,
13020 NOBS);
13021 ALLOC(rlat, double,
13022 NOBS);
13023 ALLOC(robs, double,
13024 NOBS);
13025
13026 /* Read observation data... */
13027 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13028
13029 /* Create new output file... */
13030 LOG(1, "Write profile data: %s", filename);
13031 if (!(out = fopen(filename, "w")))
13032 ERRMSG("Cannot create file!");
13033
13034 /* Write header... */
13035 fprintf(out,
13036 "# $1 = time [s]\n"
13037 "# $2 = altitude [km]\n"
13038 "# $3 = longitude [deg]\n"
13039 "# $4 = latitude [deg]\n"
13040 "# $5 = pressure [hPa]\n"
13041 "# $6 = temperature [K]\n"
13042 "# $7 = volume mixing ratio [ppv]\n"
13043 "# $8 = H2O volume mixing ratio [ppv]\n"
13044 "# $9 = O3 volume mixing ratio [ppv]\n"
13045 "# $10 = observed BT index [K]\n"
13046 "# $11 = number of observations\n");
13047
13048 /* Set grid box size... */
13049 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
13050 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
13051 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
13052
13053 /* Set vertical coordinates... */
13054 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13055 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
13056 press[iz] = P(z[iz]);
13057 }
13058
13059 /* Set horizontal coordinates... */
13060 for (int ix = 0; ix < ctl->prof_nx; ix++)
13061 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
13062 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13063 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
13064 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13065 }
13066 }
13067
13068 /* Set time interval... */
13069 const double t0 = t - 0.5 * ctl->dt_mod;
13070 const double t1 = t + 0.5 * ctl->dt_mod;
13071
13072 /* Allocate... */
13073 ALLOC(mass, double,
13074 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
13075 ALLOC(obsmean, double,
13076 ctl->prof_nx * ctl->prof_ny);
13077 ALLOC(obscount, int,
13078 ctl->prof_nx * ctl->prof_ny);
13079
13080 /* Loop over observations... */
13081 for (int i = 0; i < nobs; i++) {
13082
13083 /* Check time... */
13084 if (rt[i] < t0)
13085 continue;
13086 else if (rt[i] >= t1)
13087 break;
13088
13089 /* Check observation data... */
13090 if (!isfinite(robs[i]))
13091 continue;
13092
13093 /* Calculate indices... */
13094 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
13095 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
13096
13097 /* Check indices... */
13098 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
13099 continue;
13100
13101 /* Get mean observation index... */
13102 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
13103 obsmean[idx] += robs[i];
13104 obscount[idx]++;
13105 }
13106
13107 /* Analyze model data... */
13108 for (ip = 0; ip < atm->np; ip++) {
13109
13110 /* Check time... */
13111 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13112 continue;
13113
13114 /* Get indices... */
13115 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
13116 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
13117 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
13118
13119 /* Check indices... */
13120 if (ix < 0 || ix >= ctl->prof_nx ||
13121 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
13122 continue;
13123
13124 /* Get total mass in grid cell... */
13125 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13126 mass[idx] += atm->q[ctl->qnt_m][ip];
13127 }
13128
13129 /* Extract profiles... */
13130 for (int ix = 0; ix < ctl->prof_nx; ix++)
13131 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13132 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
13133 if (obscount[idx2] > 0) {
13134
13135 /* Check profile... */
13136 okay = 0;
13137 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13138 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13139 if (mass[idx3] > 0) {
13140 okay = 1;
13141 break;
13142 }
13143 }
13144 if (!okay)
13145 continue;
13146
13147 /* Write output... */
13148 fprintf(out, "\n");
13149
13150 /* Loop over altitudes... */
13151 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13152
13153 /* Get temperature, water vapor, and ozone... */
13155 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
13156 lon[ix], lat[iy], &temp, ci, cw, 1);
13157 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
13158 lon[ix], lat[iy], &h2o, ci, cw, 0);
13159 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
13160 lon[ix], lat[iy], &o3, ci, cw, 0);
13161
13162 /* Calculate volume mixing ratio... */
13163 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13164 vmr = MA / ctl->molmass * mass[idx3]
13165 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
13166
13167 /* Write output... */
13168 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
13169 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
13170 obsmean[idx2] / obscount[idx2], obscount[idx2]);
13171 }
13172 }
13173 }
13174
13175 /* Free... */
13176 free(mass);
13177 free(obsmean);
13178 free(obscount);
13179
13180 /* Finalize... */
13181 if (t == ctl->t_stop) {
13182
13183 /* Close output file... */
13184 fclose(out);
13185
13186 /* Free... */
13187 free(lon);
13188 free(lat);
13189 free(area);
13190 free(z);
13191 free(press);
13192 free(rt);
13193 free(rz);
13194 free(rlon);
13195 free(rlat);
13196 free(robs);
13197 }
13198}
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 13202 of file mptrac.c.

13208 {
13209
13210 static FILE *out;
13211
13212 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
13213 kw[EP];
13214
13215 static int nobs, nk;
13216
13217 /* Set timer... */
13218 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT");
13219
13220 /* Init... */
13221 if (t == ctl->t_start) {
13222
13223 /* Allocate... */
13224 ALLOC(rt, double,
13225 NOBS);
13226 ALLOC(rz, double,
13227 NOBS);
13228 ALLOC(rlon, double,
13229 NOBS);
13230 ALLOC(rlat, double,
13231 NOBS);
13232 ALLOC(robs, double,
13233 NOBS);
13234
13235 /* Read observation data... */
13236 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13237
13238 /* Read kernel data... */
13239 if (ctl->sample_kernel[0] != '-')
13240 read_kernel(ctl->sample_kernel, kz, kw, &nk);
13241
13242 /* Create output file... */
13243 LOG(1, "Write sample data: %s", filename);
13244 if (!(out = fopen(filename, "w")))
13245 ERRMSG("Cannot create file!");
13246
13247 /* Write header... */
13248 fprintf(out,
13249 "# $1 = time [s]\n"
13250 "# $2 = altitude [km]\n"
13251 "# $3 = longitude [deg]\n"
13252 "# $4 = latitude [deg]\n"
13253 "# $5 = surface area [km^2]\n"
13254 "# $6 = layer depth [km]\n"
13255 "# $7 = number of particles [1]\n"
13256 "# $8 = column density [kg/m^2]\n"
13257 "# $9 = volume mixing ratio [ppv]\n"
13258 "# $10 = observed BT index [K]\n\n");
13259
13260 /* Set latitude range, squared radius, and area... */
13261 dlat = DY2DEG(ctl->sample_dx);
13262 rmax2 = SQR(ctl->sample_dx);
13263 area = M_PI * rmax2;
13264 }
13265
13266 /* Set time interval for output... */
13267 const double t0 = t - 0.5 * ctl->dt_mod;
13268 const double t1 = t + 0.5 * ctl->dt_mod;
13269
13270 /* Loop over observations... */
13271 for (int i = 0; i < nobs; i++) {
13272
13273 /* Check time... */
13274 if (rt[i] < t0)
13275 continue;
13276 else if (rt[i] >= t1)
13277 break;
13278
13279 /* Calculate Cartesian coordinates... */
13280 double x0[3];
13281 geo2cart(0, rlon[i], rlat[i], x0);
13282
13283 /* Set pressure range... */
13284 const double rp = P(rz[i]);
13285 const double ptop = P(rz[i] + ctl->sample_dz);
13286 const double pbot = P(rz[i] - ctl->sample_dz);
13287
13288 /* Init... */
13289 double mass = 0;
13290 int np = 0;
13291
13292 /* Loop over air parcels... */
13293 //#pragma omp parallel for default(shared) reduction(+:mass,np)
13294 for (int ip = 0; ip < atm->np; ip++) {
13295
13296 /* Check time... */
13297 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13298 continue;
13299
13300 /* Check latitude... */
13301 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
13302 continue;
13303
13304 /* Check horizontal distance... */
13305 double x1[3];
13306 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13307 if (DIST2(x0, x1) > rmax2)
13308 continue;
13309
13310 /* Check pressure... */
13311 if (ctl->sample_dz > 0)
13312 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
13313 continue;
13314
13315 /* Add mass... */
13316 if (ctl->qnt_m >= 0)
13317 mass +=
13318 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13319 np++;
13320 }
13321
13322 /* Calculate column density... */
13323 const double cd = mass / (1e6 * area);
13324
13325 /* Calculate volume mixing ratio... */
13326 double vmr = 0;
13327 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
13328 if (mass > 0) {
13329
13330 /* Get temperature... */
13331 double temp;
13333 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
13334 rlon[i], rlat[i], &temp, ci, cw, 1);
13335
13336 /* Calculate volume mixing ratio... */
13337 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
13338 }
13339 } else
13340 vmr = NAN;
13341
13342 /* Write output... */
13343 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
13344 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
13345 }
13346
13347 /* Finalize...... */
13348 if (t == ctl->t_stop) {
13349
13350 /* Close output file... */
13351 fclose(out);
13352
13353 /* Free... */
13354 free(rt);
13355 free(rz);
13356 free(rlon);
13357 free(rlat);
13358 free(robs);
13359 }
13360}
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 13364 of file mptrac.c.

13368 {
13369
13370 static FILE *out;
13371
13372 static double rmax2, x0[3], x1[3];
13373
13374 /* Set timer... */
13375 SELECT_TIMER("WRITE_STATION", "OUTPUT");
13376
13377 /* Init... */
13378 if (t == ctl->t_start) {
13379
13380 /* Write info... */
13381 LOG(1, "Write station data: %s", filename);
13382
13383 /* Create new file... */
13384 if (!(out = fopen(filename, "w")))
13385 ERRMSG("Cannot create file!");
13386
13387 /* Write header... */
13388 fprintf(out,
13389 "# $1 = time [s]\n"
13390 "# $2 = altitude [km]\n"
13391 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13392 for (int iq = 0; iq < ctl->nq; iq++)
13393 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
13394 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13395 fprintf(out, "\n");
13396
13397 /* Set geolocation and search radius... */
13398 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
13399 rmax2 = SQR(ctl->stat_r);
13400 }
13401
13402 /* Set time interval for output... */
13403 const double t0 = t - 0.5 * ctl->dt_mod;
13404 const double t1 = t + 0.5 * ctl->dt_mod;
13405
13406 /* Loop over air parcels... */
13407 for (int ip = 0; ip < atm->np; ip++) {
13408
13409 /* Check time... */
13410 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13411 continue;
13412
13413 /* Check time range for station output... */
13414 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
13415 continue;
13416
13417 /* Check station flag... */
13418 if (ctl->qnt_stat >= 0)
13419 if ((int) atm->q[ctl->qnt_stat][ip])
13420 continue;
13421
13422 /* Get Cartesian coordinates... */
13423 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13424
13425 /* Check horizontal distance... */
13426 if (DIST2(x0, x1) > rmax2)
13427 continue;
13428
13429 /* Set station flag... */
13430 if (ctl->qnt_stat >= 0)
13431 atm->q[ctl->qnt_stat][ip] = 1;
13432
13433 /* Write data... */
13434 fprintf(out, "%.2f %g %g %g",
13435 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
13436 for (int iq = 0; iq < ctl->nq; iq++) {
13437 fprintf(out, " ");
13438 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
13439 }
13440 fprintf(out, "\n");
13441 }
13442
13443 /* Close file... */
13444 if (t == ctl->t_stop)
13445 fclose(out);
13446}
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 13450 of file mptrac.c.

13454 {
13455
13456 FILE *out;
13457
13458 /* Set timer... */
13459 SELECT_TIMER("WRITE_VTK", "OUTPUT");
13460
13461 /* Write info... */
13462 LOG(1, "Write VTK data: %s", filename);
13463
13464 /* Set time interval for output... */
13465 const double t0 = t - 0.5 * ctl->dt_mod;
13466 const double t1 = t + 0.5 * ctl->dt_mod;
13467
13468 /* Create file... */
13469 if (!(out = fopen(filename, "w")))
13470 ERRMSG("Cannot create file!");
13471
13472 /* Count data points... */
13473 int np = 0;
13474 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13475 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13476 continue;
13477 np++;
13478 }
13479
13480 /* Write header... */
13481 fprintf(out,
13482 "# vtk DataFile Version 3.0\n"
13483 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
13484
13485 /* Write point coordinates... */
13486 fprintf(out, "POINTS %d float\n", np);
13487 if (ctl->vtk_sphere) {
13488 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13489 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13490 continue;
13491 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
13492 + ctl->vtk_offset) / RE;
13493 const double coslat = cos(DEG2RAD(atm->lat[ip]));
13494 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
13495 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
13496 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
13497 fprintf(out, "%g %g %g\n", x, y, z);
13498 }
13499 } else
13500 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13501 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13502 continue;
13503 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
13504 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
13505 }
13506
13507 /* Write point data... */
13508 fprintf(out, "POINT_DATA %d\n", np);
13509 for (int iq = 0; iq < ctl->nq; iq++) {
13510 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
13511 ctl->qnt_name[iq]);
13512 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13513 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13514 continue;
13515 fprintf(out, "%g\n", atm->q[iq][ip]);
13516 }
13517 }
13518
13519 /* Close file... */
13520 fclose(out);
13521}