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...
 
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_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...
 
double sza_calc (const double sec, const double lon, const double lat)
 Calculates the solar zenith angle. 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.), cos_sza_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 sza = sza_calc(t, lon, lat);
109 const double denom = (sza <= sza_thresh) ? cos(sza) : cos_sza_thresh;
110 return oh * exp(-ctl->oh_chem_beta / denom);
111}
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:406
double sza_calc(const double sec, const double lon, const double lat)
Calculates the solar zenith angle.
Definition: mptrac.c:11072
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:567
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3511
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2978
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.), cos_sza_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 sza =
134 sza_calc(clim->oh.time[it], lon, clim->oh.lat[iy]);
135 const double denom =
136 (sza <= sza_thresh) ? cos(sza) : cos_sza_thresh;
137 sum += exp(-ctl->oh_chem_beta / denom);
138 n++;
139 }
140
141 /* Apply scaling factor to OH data... */
142 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
143 }
144}
double time[CT]
Time [s].
Definition: mptrac.h:3467
int np
Number of pressure levels.
Definition: mptrac.h:3464
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3476
int ntime
Number of timesteps.
Definition: mptrac.h:3458
int nlat
Number of latitudes.
Definition: mptrac.h:3461
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3470
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 148 of file mptrac.c.

153 {
154
155 /* Check pressure range... */
156 double p_help = p;
157 if (p < photo->p[photo->np - 1])
158 p_help = photo->p[photo->np - 1];
159 else if (p > photo->p[0])
160 p_help = photo->p[0];
161
162 /* Check sza range... */
163 double sza_help = sza;
164 if (sza < photo->sza[0])
165 sza_help = photo->sza[0];
166 else if (sza > photo->sza[photo->nsza - 1])
167 sza_help = photo->sza[photo->nsza - 1];
168
169 /* Check ozone column range... */
170 double o3c_help = o3c;
171 if (o3c < photo->o3c[0])
172 o3c_help = photo->o3c[0];
173 else if (o3c > photo->o3c[photo->no3c - 1])
174 o3c_help = photo->o3c[photo->no3c - 1];
175
176 /* Get indices... */
177 const int ip = locate_irr(photo->p, photo->np, p_help);
178 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
179 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
180
181 /* Interpolate photolysis rate... */
182 const double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
183 photo->p[ip + 1], rate[ip + 1][isza][io3c],
184 p_help);
185 const double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
186 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1],
187 p_help);
188 const double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
189 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c],
190 p_help);
191 const double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
192 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
193 p_help);
194 const double aux0 =
195 LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
196 const double aux1 =
197 LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
198 const double aux =
199 LIN(photo->sza[isza], aux0, photo->sza[isza + 1], aux1, sza_help);
200 return MAX(aux, 0.0);
201}
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:2886
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:2822
#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:3385
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3394
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3391
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3397
int np
Number of pressure levels.
Definition: mptrac.h:3382
int no3c
Number of total ozone columns.
Definition: mptrac.h:3388
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 205 of file mptrac.c.

208 {
209
210 /* Get seconds since begin of year... */
211 double sec = FMOD(t, 365.25 * 86400.);
212 while (sec < 0)
213 sec += 365.25 * 86400.;
214
215 /* Get indices... */
216 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
217 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
218
219 /* Interpolate tropopause pressure... */
220 const double p0 = LIN(clim->tropo_lat[ilat],
221 clim->tropo[isec][ilat],
222 clim->tropo_lat[ilat + 1],
223 clim->tropo[isec][ilat + 1], lat);
224 const double p1 = LIN(clim->tropo_lat[ilat],
225 clim->tropo[isec + 1][ilat],
226 clim->tropo_lat[ilat + 1],
227 clim->tropo[isec + 1][ilat + 1], lat);
228 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
229}
#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:3490
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3499
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3493
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3502
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3496
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 233 of file mptrac.c.

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

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

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

679 {
680
681 double min[EP], max[EP], off[EP], scl[EP];
682
683 unsigned short *sarray;
684
685 /* Allocate... */
686 ALLOC(sarray, unsigned short,
687 nxy * nz);
688
689 /* Read compressed stream and decompress array... */
690 if (decompress) {
691
692 /* Write info... */
693 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
694 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
695
696 /* Read data... */
697 FREAD(&scl, double,
698 nz,
699 inout);
700 FREAD(&off, double,
701 nz,
702 inout);
703 FREAD(sarray, unsigned short,
704 nxy * nz,
705 inout);
706
707 /* Convert to float... */
708#pragma omp parallel for default(shared)
709 for (size_t ixy = 0; ixy < nxy; ixy++)
710 for (size_t iz = 0; iz < nz; iz++)
711 array[ixy * nz + iz]
712 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
713 }
714
715 /* Compress array and output compressed stream... */
716 else {
717
718 /* Write info... */
719 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
720 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
721
722 /* Get range... */
723 for (size_t iz = 0; iz < nz; iz++) {
724 min[iz] = array[iz];
725 max[iz] = array[iz];
726 }
727 for (size_t ixy = 1; ixy < nxy; ixy++)
728 for (size_t iz = 0; iz < nz; iz++) {
729 if (array[ixy * nz + iz] < min[iz])
730 min[iz] = array[ixy * nz + iz];
731 if (array[ixy * nz + iz] > max[iz])
732 max[iz] = array[ixy * nz + iz];
733 }
734
735 /* Get offset and scaling factor... */
736 for (size_t iz = 0; iz < nz; iz++) {
737 scl[iz] = (max[iz] - min[iz]) / 65533.;
738 off[iz] = min[iz];
739 }
740
741 /* Convert to short... */
742#pragma omp parallel for default(shared)
743 for (size_t ixy = 0; ixy < nxy; ixy++)
744 for (size_t iz = 0; iz < nz; iz++)
745 if (scl[iz] != 0)
746 sarray[ixy * nz + iz] = (unsigned short)
747 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
748 else
749 sarray[ixy * nz + iz] = 0;
750
751 /* Write data... */
752 FWRITE(&scl, double,
753 nz,
754 inout);
755 FWRITE(&off, double,
756 nz,
757 inout);
758 FWRITE(sarray, unsigned short,
759 nxy * nz,
760 inout);
761 }
762
763 /* Free... */
764 free(sarray);
765}
#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

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

1008 {
1009
1010 const int
1011 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1012 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1013
1014 /* Get day of year... */
1015 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
1016 *doy = d0l[mon - 1] + day - 1;
1017 else
1018 *doy = d0[mon - 1] + day - 1;
1019}

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

1850 {
1851
1852 const int
1853 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1854 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1855
1856 int i;
1857
1858 /* Get month and day... */
1859 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
1860 for (i = 11; i > 0; i--)
1861 if (d0l[i] <= doy)
1862 break;
1863 *mon = i + 1;
1864 *day = doy - d0l[i] + 1;
1865 } else {
1866 for (i = 11; i > 0; i--)
1867 if (d0[i] <= doy)
1868 break;
1869 *mon = i + 1;
1870 *day = doy - d0[i] + 1;
1871 }
1872}

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

1879 {
1880
1881 double data[2 * EX];
1882
1883 /* Check size... */
1884 if (n > EX)
1885 ERRMSG("Too many data points!");
1886
1887 /* Allocate... */
1888 gsl_fft_complex_wavetable *wavetable =
1889 gsl_fft_complex_wavetable_alloc((size_t) n);
1890 gsl_fft_complex_workspace *workspace =
1891 gsl_fft_complex_workspace_alloc((size_t) n);
1892
1893 /* Set data (real, complex)... */
1894 for (int i = 0; i < n; i++) {
1895 data[2 * i] = fcReal[i];
1896 data[2 * i + 1] = fcImag[i];
1897 }
1898
1899 /* Calculate FFT... */
1900 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
1901
1902 /* Copy data... */
1903 for (int i = 0; i < n; i++) {
1904 fcReal[i] = data[2 * i];
1905 fcImag[i] = data[2 * i + 1];
1906 }
1907
1908 /* Free... */
1909 gsl_fft_complex_wavetable_free(wavetable);
1910 gsl_fft_complex_workspace_free(workspace);
1911}
#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 1915 of file mptrac.c.

1919 {
1920
1921 const double radius = z + RE;
1922 const double latrad = DEG2RAD(lat);
1923 const double lonrad = DEG2RAD(lon);
1924 const double coslat = cos(latrad);
1925
1926 x[0] = radius * coslat * cos(lonrad);
1927 x[1] = radius * coslat * sin(lonrad);
1928 x[2] = radius * sin(latrad);
1929}

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

1939 {
1940
1941 char repl[LEN];
1942
1943 double t6, r;
1944
1945 int year, mon, day, hour, min, sec;
1946
1947 /* Round time to fixed intervals... */
1948 if (direct == -1)
1949 t6 = floor(t / dt_met) * dt_met;
1950 else
1951 t6 = ceil(t / dt_met) * dt_met;
1952
1953 /* Decode time... */
1954 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1955
1956 /* Set filename of MPTRAC meteo files... */
1957 if (ctl->met_clams == 0) {
1958 if (ctl->met_type == 0)
1959 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1960 else if (ctl->met_type == 1)
1961 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1962 else if (ctl->met_type == 2)
1963 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1964 else if (ctl->met_type == 3)
1965 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1966 else if (ctl->met_type == 4)
1967 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1968 else if (ctl->met_type == 5)
1969 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1970 else if (ctl->met_type == 7)
1971 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
1972 sprintf(repl, "%d", year);
1973 get_met_replace(filename, "YYYY", repl);
1974 sprintf(repl, "%02d", mon);
1975 get_met_replace(filename, "MM", repl);
1976 sprintf(repl, "%02d", day);
1977 get_met_replace(filename, "DD", repl);
1978 sprintf(repl, "%02d", hour);
1979 get_met_replace(filename, "HH", repl);
1980 }
1981
1982 /* Set filename of CLaMS meteo files... */
1983 else {
1984 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1985 sprintf(repl, "%d", year);
1986 get_met_replace(filename, "YYYY", repl);
1987 sprintf(repl, "%02d", year % 100);
1988 get_met_replace(filename, "YY", repl);
1989 sprintf(repl, "%02d", mon);
1990 get_met_replace(filename, "MM", repl);
1991 sprintf(repl, "%02d", day);
1992 get_met_replace(filename, "DD", repl);
1993 sprintf(repl, "%02d", hour);
1994 get_met_replace(filename, "HH", repl);
1995 }
1996}
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:2000
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:2535
#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:2607
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:2604
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 2000 of file mptrac.c.

2003 {
2004
2005 char buffer[LEN];
2006
2007 /* Iterate... */
2008 for (int i = 0; i < 3; i++) {
2009
2010 /* Replace sub-string... */
2011 char *ch;
2012 if (!(ch = strstr(orig, search)))
2013 return;
2014 strncpy(buffer, orig, (size_t) (ch - orig));
2015 buffer[ch - orig] = 0;
2016 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
2017 orig[0] = 0;
2018 strcpy(orig, buffer);
2019 }
2020}

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

2039 {
2040
2042
2043 ctl->met_tropo = met_tropo;
2044 read_met_tropo(ctl, clim, met);
2045#pragma omp parallel for default(shared) private(ci,cw)
2046 for (int ix = 0; ix < nx; ix++)
2047 for (int iy = 0; iy < ny; iy++) {
2048 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2049 &pt[iy * nx + ix], ci, cw, 1);
2050 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2051 &ps[iy * nx + ix], ci, cw, 0);
2052 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2053 &zs[iy * nx + ix], ci, cw, 0);
2054 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2055 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2056 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2057 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2058 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2059 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2060 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2061 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2062 }
2063}
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:2324
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:10626
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:2266
#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:2738
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3675
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3585
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3591
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3678
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3660
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3618
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3657
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 2067 of file mptrac.c.

2075 {
2076
2077 /* Check longitude... */
2078 *lon2 = FMOD(lon, 360.);
2079 if (*lon2 < lons[0])
2080 *lon2 += 360;
2081 else if (*lon2 > lons[nlon - 1])
2082 *lon2 -= 360;
2083
2084 /* Check latitude... */
2085 *lat2 = lat;
2086 if (lats[0] < lats[nlat - 1])
2087 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
2088 else
2089 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
2090}

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

2108 {
2109
2110 if (init) {
2111
2112 /* Check longitude and latitude... */
2113 double lon2, lat2;
2114 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
2115 &lon2, &lat2);
2116
2117 /* Get horizontal indizes... */
2118 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
2119 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
2120
2121 /* Locate the vertical indizes for each edge of the column... */
2122 int ind[2][4];
2123 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
2124 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
2125
2126 /* Find minimum and maximum indizes... */
2127 ci[2] = ind[0][0];
2128 int k_max = ind[0][0];
2129 for (int i = 0; i < 2; i++)
2130 for (int j = 0; j < 4; j++) {
2131 if (ci[2] > ind[i][j])
2132 ci[2] = ind[i][j];
2133 if (k_max < ind[i][j])
2134 k_max = ind[i][j];
2135 }
2136
2137 /* Get weighting factors for time, longitude and latitude... */
2138 cw[3] = (ts - met0->time) / (met1->time - met0->time);
2139 cw[0] = (lon2 - met0->lon[ci[0]]) /
2140 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
2141 cw[1] = (lat2 - met0->lat[ci[1]]) /
2142 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
2143
2144 /* Interpolate in time at the lowest level... */
2145 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
2146 - heights0[ci[0]][ci[1]][ci[2]])
2147 + heights0[ci[0]][ci[1]][ci[2]];
2148 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
2149 - heights0[ci[0]][ci[1] + 1][ci[2]])
2150 + heights0[ci[0]][ci[1] + 1][ci[2]];
2151 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
2152 - heights0[ci[0] + 1][ci[1]][ci[2]])
2153 + heights0[ci[0] + 1][ci[1]][ci[2]];
2154 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
2155 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
2156 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
2157
2158 /* Interpolate in latitude direction... */
2159 double height0 = cw[1] * (height01 - height00) + height00;
2160 double height1 = cw[1] * (height11 - height10) + height10;
2161
2162 /* Interpolate in longitude direction... */
2163 double height_bot = cw[0] * (height1 - height0) + height0;
2164
2165 /* Interpolate in time at the upper level... */
2166 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2167 - heights0[ci[0]][ci[1]][ci[2] + 1])
2168 + heights0[ci[0]][ci[1]][ci[2] + 1];
2169 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2170 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2171 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2172 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2173 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2174 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2175 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2176 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2177 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2178
2179 /* Interpolate in latitude direction... */
2180 height0 = cw[1] * (height01 - height00) + height00;
2181 height1 = cw[1] * (height11 - height10) + height10;
2182
2183 /* Interpolate in longitude direction... */
2184 double height_top = cw[0] * (height1 - height0) + height0;
2185
2186 /* Search at higher levels if height is not in box... */
2187 while (((heights0[0][0][0] > heights0[0][0][1]) &&
2188 ((height_bot <= height) || (height_top > height))
2189 && (height_bot >= height) && (ci[2] < k_max))
2190 ||
2191 ((heights0[0][0][0] < heights0[0][0][1]) &&
2192 ((height_bot >= height) || (height_top < height))
2193 && (height_bot <= height) && (ci[2] < k_max))
2194 ) {
2195
2196 ci[2]++;
2197 height_bot = height_top;
2198
2199 /* Interpolate in time at the next level... */
2200 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2201 - heights0[ci[0]][ci[1]][ci[2] + 1])
2202 + heights0[ci[0]][ci[1]][ci[2] + 1];
2203 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2204 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2205 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2206 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2207 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2208 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2209 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2210 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2211 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2212
2213 /* Interpolate in latitude direction... */
2214 height0 = cw[1] * (height01 - height00) + height00;
2215 height1 = cw[1] * (height11 - height10) + height10;
2216
2217 /* Interpolate in longitude direction... */
2218 height_top = cw[0] * (height1 - height0) + height0;
2219 }
2220
2221 /* Get vertical weighting factors... */
2222 cw[2] = (height - height_bot)
2223 / (height_top - height_bot);
2224 }
2225
2226 /* Calculate the needed array values... */
2227 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
2228 - array0[ci[0]][ci[1]][ci[2]])
2229 + array0[ci[0]][ci[1]][ci[2]];
2230 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
2231 - array0[ci[0] + 1][ci[1]][ci[2]])
2232 + array0[ci[0] + 1][ci[1]][ci[2]];
2233 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
2234 - array0[ci[0]][ci[1] + 1][ci[2]])
2235 + array0[ci[0]][ci[1] + 1][ci[2]];
2236 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
2237 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
2238 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
2239 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
2240 - array0[ci[0]][ci[1]][ci[2] + 1])
2241 + array0[ci[0]][ci[1]][ci[2] + 1];
2242 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2243 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2244 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2245 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2246 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2247 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2248 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2249 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2250 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2251
2252 const double array00 = cw[0] * (array100 - array000) + array000;
2253 const double array10 = cw[0] * (array110 - array010) + array010;
2254 const double array01 = cw[0] * (array101 - array001) + array001;
2255 const double array11 = cw[0] * (array111 - array011) + array011;
2256
2257 const double aux0 = cw[1] * (array10 - array00) + array00;
2258 const double aux1 = cw[1] * (array11 - array01) + array01;
2259
2260 /* Interpolate vertically... */
2261 *var = cw[2] * (aux1 - aux0) + aux0;
2262}
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:2905
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:2067
int nx
Number of longitudes.
Definition: mptrac.h:3552
int ny
Number of latitudes.
Definition: mptrac.h:3555
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3564
int npl
Number of model levels.
Definition: mptrac.h:3561
double time
Time [s].
Definition: mptrac.h:3549
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3567
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 2266 of file mptrac.c.

2275 {
2276
2277 /* Initialize interpolation... */
2278 if (init) {
2279
2280 /* Check longitude and latitude... */
2281 double lon2, lat2;
2282 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2283 &lon2, &lat2);
2284
2285 /* Get interpolation indices... */
2286 ci[0] = locate_irr(met->p, met->np, p);
2287 ci[1] = locate_reg(met->lon, met->nx, lon2);
2288 ci[2] = locate_irr(met->lat, met->ny, lat2);
2289
2290 /* Get interpolation weights... */
2291 cw[0] = (met->p[ci[0] + 1] - p)
2292 / (met->p[ci[0] + 1] - met->p[ci[0]]);
2293 cw[1] = (met->lon[ci[1] + 1] - lon2)
2294 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2295 cw[2] = (met->lat[ci[2] + 1] - lat2)
2296 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2297 }
2298
2299 /* Interpolate vertically... */
2300 const double aux00 =
2301 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
2302 + array[ci[1]][ci[2]][ci[0] + 1];
2303 const double aux01 =
2304 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
2305 array[ci[1]][ci[2] + 1][ci[0] + 1])
2306 + array[ci[1]][ci[2] + 1][ci[0] + 1];
2307 const double aux10 =
2308 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
2309 array[ci[1] + 1][ci[2]][ci[0] + 1])
2310 + array[ci[1] + 1][ci[2]][ci[0] + 1];
2311 const double aux11 =
2312 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
2313 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
2314 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
2315
2316 /* Interpolate horizontally... */
2317 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2318 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2319 *var = cw[1] * (aux0 - aux1) + aux1;
2320}
int np
Number of pressure levels.
Definition: mptrac.h:3558
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3570
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 2324 of file mptrac.c.

2332 {
2333
2334 /* Initialize interpolation... */
2335 if (init) {
2336
2337 /* Check longitude and latitude... */
2338 double lon2, lat2;
2339 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2340 &lon2, &lat2);
2341
2342 /* Get interpolation indices... */
2343 ci[1] = locate_reg(met->lon, met->nx, lon2);
2344 ci[2] = locate_irr(met->lat, met->ny, lat2);
2345
2346 /* Get interpolation weights... */
2347 cw[1] = (met->lon[ci[1] + 1] - lon2)
2348 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2349 cw[2] = (met->lat[ci[2] + 1] - lat2)
2350 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2351 }
2352
2353 /* Set variables... */
2354 const double aux00 = array[ci[1]][ci[2]];
2355 const double aux01 = array[ci[1]][ci[2] + 1];
2356 const double aux10 = array[ci[1] + 1][ci[2]];
2357 const double aux11 = array[ci[1] + 1][ci[2] + 1];
2358
2359 /* Interpolate horizontally... */
2360 if (isfinite(aux00) && isfinite(aux01)
2361 && isfinite(aux10) && isfinite(aux11)) {
2362 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2363 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2364 *var = cw[1] * (aux0 - aux1) + aux1;
2365 } else {
2366 if (cw[2] < 0.5) {
2367 if (cw[1] < 0.5)
2368 *var = aux11;
2369 else
2370 *var = aux01;
2371 } else {
2372 if (cw[1] < 0.5)
2373 *var = aux10;
2374 else
2375 *var = aux00;
2376 }
2377 }
2378}
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 2382 of file mptrac.c.

2394 {
2395
2396 double var0, var1;
2397
2398 /* Spatial interpolation... */
2399 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
2400 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
2401
2402 /* Get weighting factor... */
2403 const double wt = (met1->time - ts) / (met1->time - met0->time);
2404
2405 /* Interpolate... */
2406 *var = wt * (var0 - var1) + var1;
2407}
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 2411 of file mptrac.c.

2422 {
2423
2424 double var0, var1;
2425
2426 /* Spatial interpolation... */
2427 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
2428 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
2429
2430 /* Get weighting factor... */
2431 const double wt = (met1->time - ts) / (met1->time - met0->time);
2432
2433 /* Interpolate... */
2434 if (isfinite(var0) && isfinite(var1))
2435 *var = wt * (var0 - var1) + var1;
2436 else if (wt < 0.5)
2437 *var = var1;
2438 else
2439 *var = var0;
2440}
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 2444 of file mptrac.c.

2458 {
2459
2460 double mean = 0;
2461
2462 int n = 0;
2463
2464 /* Check longitude and latitude... */
2465 double lon2, lat2;
2466 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
2467
2468 /* Get indices... */
2469 const int ix = locate_reg(lons, (int) nlon, lon2);
2470 const int iy = locate_irr(lats, (int) nlat, lat2);
2471
2472 /* Calculate standard deviation... */
2473 *sigma = 0;
2474 for (int dx = 0; dx < 2; dx++)
2475 for (int dy = 0; dy < 2; dy++) {
2476 if (isfinite(array0[ix + dx][iy + dy])) {
2477 mean += array0[ix + dx][iy + dy];
2478 *sigma += SQR(array0[ix + dx][iy + dy]);
2479 n++;
2480 }
2481 if (isfinite(array1[ix + dx][iy + dy])) {
2482 mean += array1[ix + dx][iy + dy];
2483 *sigma += SQR(array1[ix + dx][iy + dy]);
2484 n++;
2485 }
2486 }
2487 if (n > 0)
2488 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
2489
2490 /* Linear interpolation... */
2491 if (method == 1 && isfinite(array0[ix][iy])
2492 && isfinite(array0[ix][iy + 1])
2493 && isfinite(array0[ix + 1][iy])
2494 && isfinite(array0[ix + 1][iy + 1])
2495 && isfinite(array1[ix][iy])
2496 && isfinite(array1[ix][iy + 1])
2497 && isfinite(array1[ix + 1][iy])
2498 && isfinite(array1[ix + 1][iy + 1])) {
2499
2500 const double aux00 = LIN(lons[ix], array0[ix][iy],
2501 lons[ix + 1], array0[ix + 1][iy], lon2);
2502 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
2503 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2504 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2505
2506 const double aux10 = LIN(lons[ix], array1[ix][iy],
2507 lons[ix + 1], array1[ix + 1][iy], lon2);
2508 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
2509 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2510 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2511
2512 *var = LIN(time0, aux0, time1, aux1, time);
2513 }
2514
2515 /* Nearest neighbor interpolation... */
2516 else {
2517 const double aux00 = NN(lons[ix], array0[ix][iy],
2518 lons[ix + 1], array0[ix + 1][iy], lon2);
2519 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
2520 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2521 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2522
2523 const double aux10 = NN(lons[ix], array1[ix][iy],
2524 lons[ix + 1], array1[ix + 1][iy], lon2);
2525 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
2526 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2527 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2528
2529 *var = NN(time0, aux0, time1, aux1, time);
2530 }
2531}
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1386
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1696
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 2535 of file mptrac.c.

2543 {
2544
2545 struct tm t0, *t1;
2546
2547 t0.tm_year = 100;
2548 t0.tm_mon = 0;
2549 t0.tm_mday = 1;
2550 t0.tm_hour = 0;
2551 t0.tm_min = 0;
2552 t0.tm_sec = 0;
2553
2554 const time_t jsec0 = (time_t) jsec + timegm(&t0);
2555 t1 = gmtime(&jsec0);
2556
2557 *year = t1->tm_year + 1900;
2558 *mon = t1->tm_mon + 1;
2559 *day = t1->tm_mday;
2560 *hour = t1->tm_hour;
2561 *min = t1->tm_min;
2562 *sec = t1->tm_sec;
2563 *remain = jsec - floor(jsec);
2564}

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

2572 {
2573
2574 /* Check number of data points... */
2575 if (nk < 2)
2576 return 1.0;
2577
2578 /* Get altitude... */
2579 const double z = Z(p);
2580
2581 /* Get weighting factor... */
2582 if (z < kz[0])
2583 return kw[0];
2584 else if (z > kz[nk - 1])
2585 return kw[nk - 1];
2586 else {
2587 const int idx = locate_irr(kz, nk, z);
2588 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
2589 }
2590}
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 2594 of file mptrac.c.

2596 {
2597
2598 /*
2599 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
2600 and water vapor volume mixing ratio [1].
2601
2602 Reference: https://en.wikipedia.org/wiki/Lapse_rate
2603 */
2604
2605 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
2606
2607 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
2608}
#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 2612 of file mptrac.c.

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

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

2825 {
2826
2827 int ilo = 0;
2828 int ihi = n - 1;
2829 int i = (ihi + ilo) >> 1;
2830
2831 if (xx[i] < xx[i + 1])
2832 while (ihi > ilo + 1) {
2833 i = (ihi + ilo) >> 1;
2834 if (xx[i] > x)
2835 ihi = i;
2836 else
2837 ilo = i;
2838 } else
2839 while (ihi > ilo + 1) {
2840 i = (ihi + ilo) >> 1;
2841 if (xx[i] <= x)
2842 ihi = i;
2843 else
2844 ilo = i;
2845 }
2846
2847 return ilo;
2848}

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

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

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

2889 {
2890
2891 /* Calculate index... */
2892 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2893
2894 /* Check range... */
2895 if (i < 0)
2896 return 0;
2897 else if (i > n - 2)
2898 return n - 2;
2899 else
2900 return i;
2901}

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

2911 {
2912
2913 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2914 np, height_ap, 0);
2915 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2916 np, height_ap, ind[0]);
2917 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2918 np, height_ap, ind[1]);
2919 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2920 np, height_ap, ind[2]);
2921}
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:2852
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 2925 of file mptrac.c.

2930 {
2931
2932 /* Set timer... */
2933 SELECT_TIMER("MODULE_ADVECT", "PHYSICS", NVTX_GPU);
2934
2935 /* Use omega vertical velocity... */
2936 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2937
2938 /* Loop over particles... */
2939 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2940
2941 /* Init... */
2943 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2944 x[3] = { 0, 0, 0 };
2945
2946 /* Loop over integration nodes... */
2947 for (int i = 0; i < ctl->advect; i++) {
2948
2949 /* Set position... */
2950 if (i == 0) {
2951 dts = 0.0;
2952 x[0] = atm->lon[ip];
2953 x[1] = atm->lat[ip];
2954 x[2] = atm->p[ip];
2955 } else {
2956 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2957 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2958 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2959 x[2] = atm->p[ip] + dts * w[i - 1];
2960 }
2961 const double tm = atm->time[ip] + dts;
2962
2963 /* Interpolate meteo data on pressure levels... */
2964 if (ctl->advect_vert_coord == 0) {
2965 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2966 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2967 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2968 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2969 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2970 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2971 }
2972
2973 /* Interpolate meteo data on model levels... */
2974 else {
2975 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
2976 met1, met1->pl, met1->ul,
2977 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2978 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
2979 met1, met1->pl, met1->vl,
2980 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2981 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
2982 met1, met1->pl, met1->wl,
2983 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2984 }
2985
2986 /* Get mean wind... */
2987 double k = 1.0;
2988 if (ctl->advect == 2)
2989 k = (i == 0 ? 0.0 : 1.0);
2990 else if (ctl->advect == 4)
2991 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2992 um += k * u[i];
2993 vm += k * v[i];
2994 wm += k * w[i];
2995 }
2996
2997 /* Set new position... */
2998 atm->time[ip] += cache->dt[ip];
2999 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3000 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3001 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3002 atm->p[ip] += cache->dt[ip] * wm;
3003 }
3004 }
3005
3006 /* Use zeta or eta vertical velocity... */
3007 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
3008
3009 /* Select quantity index depending on coordinate... */
3010 const int qnt = (ctl->advect_vert_coord == 1
3011 ? ctl->qnt_zeta : ctl->qnt_eta);
3012
3013 /* Loop over particles... */
3014 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3015
3016 /* Convert pressure to vertical coordinate (zeta or eta)... */
3018 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
3019 met1, met1->pl, met1->zetal,
3020 atm->time[ip], atm->p[ip],
3021 atm->lon[ip], atm->lat[ip],
3022 &atm->q[qnt][ip], ci, cw, 1);
3023
3024 /* Init... */
3025 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
3026 wdotm = 0, x[3] = { 0, 0, 0 };
3027
3028 /* Loop over integration nodes (Runge–Kutta steps)... */
3029 for (int i = 0; i < ctl->advect; i++) {
3030
3031 /* Set position... */
3032 if (i == 0) {
3033 dts = 0.0;
3034 x[0] = atm->lon[ip];
3035 x[1] = atm->lat[ip];
3036 x[2] = atm->q[qnt][ip];
3037 } else {
3038 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3039 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
3040 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
3041 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
3042 }
3043
3044 const double tm = atm->time[ip] + dts;
3045
3046 /* Interpolate meteo data... */
3047 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
3048 met1, met1->zetal, met1->ul,
3049 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3050 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
3051 met1, met1->zetal, met1->vl,
3052 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3053 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
3054 met1, met1->zetal, met1->zeta_dotl,
3055 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
3056
3057 /* Compute Runge–Kutta weights... */
3058 double k = 1.0;
3059 if (ctl->advect == 2)
3060 k = (i == 0 ? 0.0 : 1.0);
3061 else if (ctl->advect == 4)
3062 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3063
3064 um += k * u[i];
3065 vm += k * v[i];
3066 wdotm += k * wdot[i];
3067 }
3068
3069 /* Update particle position... */
3070 atm->time[ip] += cache->dt[ip];
3071 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3072 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3073 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3074 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
3075
3076 /* Convert vertical coordinate (zeta or eta) back to pressure... */
3077 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
3078 met1, met1->zetal, met1->pl,
3079 atm->time[ip],
3080 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
3081 &atm->p[ip], ci, cw, 1);
3082 }
3083 }
3084}
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:2382
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:2094
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1413
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:614
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:2123
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:632
double time[NP]
Time [s].
Definition: mptrac.h:3298
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3307
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3304
int np
Number of air parcels.
Definition: mptrac.h:3295
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3310
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3301
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3368
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2487
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2773
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2478
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:2777
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3711
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3669
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3705
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3702
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3663
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3699
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3666
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3696
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3708
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 3088 of file mptrac.c.

3093 {
3094
3095 /* Check parameters... */
3096 if (ctl->advect_vert_coord != 1)
3097 return;
3098
3099 /* Set timer... */
3100 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS", NVTX_GPU);
3101
3102 /* Loop over particles... */
3103 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
3104
3105 /* Initialize pressure consistent with zeta... */
3107 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
3108 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
3109 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
3110 }
3111}
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 3115 of file mptrac.c.

3121 {
3122
3123 /* Set timer... */
3124 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS", NVTX_GPU);
3125
3126 /* Check quantity flags... */
3127 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
3128 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
3129 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
3130 return;
3131
3132 /* Loop over particles... */
3133 PARTICLE_LOOP(0, atm->np, 1,
3134 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3135
3136 /* Check latitude and pressure range... */
3137 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
3138 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
3139 continue;
3140
3141 /* Check surface layer... */
3142 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
3143 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
3144
3145 /* Get surface pressure... */
3146 double ps;
3148 INTPOL_2D(ps, 1);
3149
3150 /* Check pressure... */
3151 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
3152 continue;
3153
3154 /* Check height... */
3155 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
3156 continue;
3157
3158 /* Check zeta range... */
3159 if (ctl->bound_zetas > 0) {
3160 double t;
3161 INTPOL_3D(t, 1);
3162 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
3163 continue;
3164 }
3165
3166 /* Check planetary boundary layer... */
3167 if (ctl->bound_pbl) {
3168 double pbl;
3169 INTPOL_2D(pbl, 0);
3170 if (atm->p[ip] < pbl)
3171 continue;
3172 }
3173 }
3174
3175 /* Set mass and volume mixing ratio... */
3176 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
3177 atm->q[ctl->qnt_m][ip] =
3178 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
3179 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
3180 atm->q[ctl->qnt_vmr][ip] =
3181 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
3182
3183 /* Set CFC-10 volume mixing ratio... */
3184 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
3185 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
3186
3187 /* Set CFC-11 volume mixing ratio... */
3188 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
3189 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
3190
3191 /* Set CFC-12 volume mixing ratio... */
3192 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
3193 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
3194
3195 /* Set N2O volume mixing ratio... */
3196 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
3197 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
3198
3199 /* Set SF6 volume mixing ratio... */
3200 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
3201 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
3202
3203 /* Set age of air... */
3204 if (ctl->qnt_aoa >= 0)
3205 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
3206 }
3207}
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:388
#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:3529
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3535
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3523
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3526
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3532
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2556
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2295
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2565
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2903
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2852
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2550
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2825
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2298
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2840
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2858
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2846
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2831
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2837
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2834
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2559
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2553
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2562
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2849
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2828
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2843
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2894
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2906
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2897
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2900
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2855
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 3211 of file mptrac.c.

3216 {
3217
3218 /* Check quantities... */
3219 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
3220 return;
3221 if (ctl->molmass <= 0)
3222 ERRMSG("Molar mass is not defined!");
3223
3224 /* Set timer... */
3225 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS", NVTX_GPU);
3226
3227 /* Allocate... */
3228 const int ensemble_mode = (ctl->nens > 0);
3229 const int np = atm->np;
3230 const int nz = ctl->chemgrid_nz;
3231 const int nx = ctl->chemgrid_nx;
3232 const int ny = ctl->chemgrid_ny;
3233 const int ngrid = nx * ny * nz;
3234 const int nens = ensemble_mode ? ctl->nens : 1;
3235
3236 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
3237 double *restrict const press =
3238 (double *) malloc((size_t) nz * sizeof(double));
3239 double *restrict const mass =
3240 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
3241 double *restrict const area =
3242 (double *) malloc((size_t) ny * sizeof(double));
3243 double *restrict const lon =
3244 (double *) malloc((size_t) nx * sizeof(double));
3245 double *restrict const lat =
3246 (double *) malloc((size_t) ny * sizeof(double));
3247
3248 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3249 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3250 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3251
3252 /* Set grid box size... */
3253 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
3254 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
3255 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
3256
3257 /* Set vertical coordinates... */
3258#ifdef _OPENACC
3259#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])
3260#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
3261#pragma acc parallel loop independent gang vector
3262#else
3263#pragma omp parallel for default(shared)
3264#endif
3265 for (int iz = 0; iz < nz; iz++) {
3266 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
3267 press[iz] = P(z[iz]);
3268 }
3269
3270 /* Set time interval for output... */
3271 const double t0 = tt - 0.5 * ctl->dt_mod;
3272 const double t1 = tt + 0.5 * ctl->dt_mod;
3273
3274 /* Get indices... */
3275#ifdef _OPENACC
3276#pragma acc parallel loop independent gang vector
3277#else
3278#pragma omp parallel for default(shared)
3279#endif
3280 for (int ip = 0; ip < np; ip++) {
3281 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
3282 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
3283 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
3284 if (atm->time[ip] < t0 || atm->time[ip] > t1
3285 || ixs[ip] < 0 || ixs[ip] >= nx
3286 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
3287 izs[ip] = -1;
3288 }
3289
3290 /* Set horizontal coordinates... */
3291#ifdef _OPENACC
3292#pragma acc parallel loop independent gang vector
3293#else
3294#pragma omp parallel for default(shared)
3295#endif
3296 for (int ix = 0; ix < nx; ix++)
3297 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3298
3299#ifdef _OPENACC
3300#pragma acc parallel loop independent gang vector
3301#else
3302#pragma omp parallel for default(shared)
3303#endif
3304 for (int iy = 0; iy < ny; iy++) {
3305 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3306 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3307 }
3308
3309 /* Get mass per grid box... */
3310#ifdef _OPENACC
3311#pragma acc parallel loop independent gang vector
3312#endif
3313 for (int ip = 0; ip < np; ip++) {
3314 if (izs[ip] >= 0) {
3315 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3316 if (ensemble_mode) {
3317 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3318 mass_idx += ens * ngrid;
3319 }
3320#ifdef _OPENACC
3321#pragma acc atomic update
3322#endif
3323 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
3324 }
3325 }
3326
3327 /* Assign grid data to air parcels ... */
3328#ifdef _OPENACC
3329#pragma acc parallel loop independent gang vector
3330#else
3331#pragma omp parallel for default(shared)
3332#endif
3333 for (int ip = 0; ip < np; ip++)
3334 if (izs[ip] >= 0) {
3335
3336 /* Interpolate temperature... */
3337 double temp;
3339 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
3340 press[izs[ip]],
3341 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
3342
3343 /* Set mass... */
3344 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3345 if (ensemble_mode) {
3346 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3347 mass_idx += ens * ngrid;
3348 }
3349
3350 /* Calculate volume mixing ratio... */
3351 const double m = mass[mass_idx];
3352 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
3353 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
3354 }
3355
3356 /* Free... */
3357#ifdef _OPENACC
3358#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
3359#endif
3360 free(mass);
3361 free(lon);
3362 free(lat);
3363 free(area);
3364 free(z);
3365 free(press);
3366 free(ixs);
3367 free(iys);
3368 free(izs);
3369}
#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:2864
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2951
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2948
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2966
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2969
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2957
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2960
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2583
int nens
Number of ensembles.
Definition: mptrac.h:3117
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2945
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2954
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2963
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2289
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2520
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.
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 3373 of file mptrac.c.

3379 {
3380
3381 /* Set timer... */
3382 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS", NVTX_GPU);
3383
3384 /* Loop over particles... */
3385 PARTICLE_LOOP(0, atm->np, 0,
3386 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3387
3388 /* Set H2O and O3 using meteo data... */
3390 if (ctl->qnt_Ch2o >= 0) {
3391 double h2o;
3392 INTPOL_3D(h2o, 1);
3393 SET_ATM(qnt_Ch2o, h2o);
3394 }
3395 if (ctl->qnt_Co3 >= 0) {
3396 double o3;
3397 INTPOL_3D(o3, 1);
3398 SET_ATM(qnt_Co3, o3);
3399 }
3400
3401 /* Set radical species... */
3402 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
3403 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3404 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
3405 atm->lat[ip], atm->p[ip]));
3406 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
3407 atm->lat[ip], atm->p[ip]));
3408 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
3409 atm->lat[ip], atm->p[ip]));
3410 }
3411}
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:3517
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3520
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3514
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2523
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2526
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 3415 of file mptrac.c.

3420 {
3421
3422 /* Set timer... */
3423 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
3424
3425 /* Create random numbers... */
3426 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
3427
3428 /* Loop over particles... */
3429 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3430
3431 /* Interpolate surface pressure... */
3432 double ps;
3434 INTPOL_2D(ps, 1);
3435
3436 /* Initialize pressure range for vertical mixing... */
3437 double pbot = ps, ptop = ps;
3438
3439 /* Mixing in the PBL... */
3440 if (ctl->conv_mix_pbl) {
3441
3442 /* Interpolate PBL... */
3443 double pbl;
3444 INTPOL_2D(pbl, 0);
3445
3446 /* Set pressure range... */
3447 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
3448 }
3449
3450 /* Convective mixing... */
3451 if (ctl->conv_cape >= 0) {
3452
3453 /* Interpolate CAPE, CIN, and equilibrium level... */
3454 double cape, cin, pel;
3455 INTPOL_2D(cape, 0);
3456 INTPOL_2D(cin, 0);
3457 INTPOL_2D(pel, 0);
3458
3459 /* Set pressure range... */
3460 if (isfinite(cape) && cape >= ctl->conv_cape
3461 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
3462 ptop = GSL_MIN(ptop, pel);
3463 }
3464
3465 /* Apply vertical mixing... */
3466 if (ptop != pbot && atm->p[ip] >= ptop) {
3467
3468 /* Get density range... */
3469 double tbot, ttop;
3470 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
3471 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
3472 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
3473 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
3474 const double rhobot = pbot / tbot;
3475 const double rhotop = ptop / ttop;
3476
3477 /* Get new density... */
3478 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
3479
3480 /* Get pressure... */
3481 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
3482 }
3483 }
3484}
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:4588
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3365
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2816
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2813
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2810
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2819
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 3528 of file mptrac.c.

3532 {
3533
3534 /* Set timer... */
3535 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
3536
3537 /* Check quantity flags... */
3538 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3539 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3540
3541 /* Loop over particles... */
3542 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
3543
3544 /* Get weighting factor... */
3545 const double w = tropo_weight(clim, atm, ip);
3546
3547 /* Set lifetime... */
3548 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
3549
3550 /* Calculate exponential decay... */
3551 const double aux = exp(-cache->dt[ip] / tdec);
3552 if (ctl->qnt_m >= 0) {
3553 if (ctl->qnt_mloss_decay >= 0)
3554 atm->q[ctl->qnt_mloss_decay][ip]
3555 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3556 atm->q[ctl->qnt_m][ip] *= aux;
3557 if (ctl->qnt_loss_rate >= 0)
3558 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
3559 }
3560 if (ctl->qnt_vmr >= 0)
3561 atm->q[ctl->qnt_vmr][ip] *= aux;
3562 }
3563}
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:11247
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2454
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2451
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2870
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2867
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 3567 of file mptrac.c.

3572 {
3573
3574 /* Set timer... */
3575 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS", NVTX_GPU);
3576
3577 /* Create random numbers... */
3578 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3579
3580 /* Loop over particles... */
3581 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3582
3583 /* Get indices... */
3584 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
3585 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
3586 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
3587
3588 /* Get standard deviations of local wind data... */
3589 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
3590 for (int i = 0; i < 2; i++)
3591 for (int j = 0; j < 2; j++)
3592 for (int k = 0; k < 2; k++) {
3593 umean += met0->u[ix + i][iy + j][iz + k];
3594 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
3595 vmean += met0->v[ix + i][iy + j][iz + k];
3596 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
3597 wmean += met0->w[ix + i][iy + j][iz + k];
3598 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
3599
3600 umean += met1->u[ix + i][iy + j][iz + k];
3601 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
3602 vmean += met1->v[ix + i][iy + j][iz + k];
3603 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
3604 wmean += met1->w[ix + i][iy + j][iz + k];
3605 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
3606 }
3607 usig = usig / 16.f - SQR(umean / 16.f);
3608 usig = (usig > 0 ? sqrtf(usig) : 0);
3609 vsig = vsig / 16.f - SQR(vmean / 16.f);
3610 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
3611 wsig = wsig / 16.f - SQR(wmean / 16.f);
3612 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
3613
3614 /* Set temporal correlations for mesoscale fluctuations... */
3615 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
3616 const double r2 = sqrt(1 - r * r);
3617
3618 /* Calculate horizontal mesoscale wind fluctuations... */
3619 if (ctl->turb_mesox > 0) {
3620 cache->uvwp[ip][0] =
3621 (float) (r * cache->uvwp[ip][0] +
3622 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
3623 atm->lon[ip] +=
3624 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3625
3626 cache->uvwp[ip][1] =
3627 (float) (r * cache->uvwp[ip][1] +
3628 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
3629 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3630 }
3631
3632 /* Calculate vertical mesoscale wind fluctuations... */
3633 if (ctl->turb_mesoz > 0) {
3634 cache->uvwp[ip][2] =
3635 (float) (r * cache->uvwp[ip][2] +
3636 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
3637 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
3638 }
3639 }
3640}
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3362
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2807
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2593
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2804
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 3644 of file mptrac.c.

3649 {
3650
3651 /* Set timer... */
3652 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS", NVTX_GPU);
3653
3654 /* Create random numbers... */
3655 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3656
3657 /* Loop over particles... */
3658 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3659
3660 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
3661 tau_u = 300., tau_w = 100.;
3662
3663 /* Get surface and PBL pressure... */
3664 double pbl, ps;
3666 INTPOL_2D(ps, 1);
3667 INTPOL_2D(pbl, 0);
3668
3669 /* Boundary layer... */
3670 if (atm->p[ip] >= pbl) {
3671
3672 /* Calculate heights... */
3673 const double p = MIN(atm->p[ip], ps);
3674 const double zs = Z(ps);
3675 const double z = 1e3 * (Z(p) - zs);
3676 const double zi = 1e3 * (Z(pbl) - zs);
3677 const double zratio = z / zi;
3678
3679 /* Calculate friction velocity... */
3680 double ess, nss, h2o, t;
3681 INTPOL_2D(ess, 0);
3682 INTPOL_2D(nss, 0);
3683 INTPOL_3D(t, 1);
3684 INTPOL_3D(h2o, 0);
3685 const double rho = RHO(p, TVIRT(t, h2o));
3686 const double tau = sqrt(SQR(ess) + SQR(nss));
3687 const double ustar = sqrt(tau / rho);
3688
3689 /* Get surface sensible heat flux... */
3690 double shf;
3691 INTPOL_2D(shf, 1);
3692
3693 /* Stable or neutral conditions... */
3694 if (shf <= 0) {
3695
3696 /* Calcalute turbulent velocity variances... */
3697 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
3698 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
3699
3700 /* Calculate derivative dsig_w/dz... */
3701 dsigw_dz = -1.3 * ustar / zi;
3702
3703 /* Calcalute Lagrangian timescales... */
3704 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
3705 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
3706 }
3707
3708 /* Unstable conditions... */
3709 else {
3710
3711 /* Convective velocity... */
3712 const double wstar =
3713 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
3714
3715 /* Calcalute turbulent velocity variances... */
3716 sig_u = 1e-2
3717 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
3718 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
3719 * pow(zratio, 2.0 / 3.0)
3720 + (1.8 - 1.4 * zratio) * SQR(ustar));
3721
3722 /* Calculate derivative dsig_w/dz... */
3723 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
3724 * (0.8 *
3725 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
3726 - 1.8 * pow(zratio, 2.0 / 3.0)));
3727
3728 /* Calculate Lagrangian timescales... */
3729 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
3730 const double eps =
3731 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
3732 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
3733 tau_u = 2 * SQR(sig_u) / (C0 * eps);
3734 tau_w = 2 * SQR(sig_w) / (C0 * eps);
3735 }
3736 }
3737
3738 /* Set minimum values... */
3739 sig_u = MAX(sig_u, 0.25);
3740 sig_w = MAX(sig_w, 0.1);
3741 tau_u = MAX(tau_u, 300.);
3742 tau_w = MAX(tau_w, 100.);
3743
3744 /* Update perturbations... */
3745 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
3746 const double ru2 = sqrt(1.0 - SQR(ru));
3747 cache->uvwp[ip][0]
3748 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
3749 cache->uvwp[ip][1]
3750 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
3751
3752 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
3753 const double rw2 = sqrt(1.0 - SQR(rw));
3754 cache->uvwp[ip][2]
3755 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
3756 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
3757
3758 /* Calculate new air parcel position... */
3759 atm->lon[ip] +=
3760 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3761 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3762 atm->p[ip] +=
3763 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
3764 }
3765}
#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 3769 of file mptrac.c.

3775 {
3776
3777 /* Set timer... */
3778 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS", NVTX_GPU);
3779
3780 /* Create random numbers... */
3781 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3782
3783 /* Loop over particles... */
3784 PARTICLE_LOOP(0, atm->np, 1,
3785 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3786
3787 /* Get PBL and surface pressure... */
3788 double pbl, ps;
3790 INTPOL_2D(pbl, 1);
3791 INTPOL_2D(ps, 0);
3792
3793 /* Get weighting factors... */
3794 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
3795 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
3796 const double wstrat = 1.0 - wpbl - wtrop;
3797
3798 /* Set diffusivity... */
3799 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
3800 + wstrat * ctl->turb_dx_strat;
3801 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
3802 + wstrat * ctl->turb_dz_strat;
3803
3804 /* Horizontal turbulent diffusion... */
3805 if (dx > 0) {
3806 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
3807 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
3808 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
3809 }
3810
3811 /* Vertical turbulent diffusion... */
3812 if (dz > 0) {
3813 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
3814 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
3815 }
3816 }
3817}
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:6945
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2798
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2792
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2789
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2786
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2801
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2795
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 3821 of file mptrac.c.

3826 {
3827
3828 /* Set timer... */
3829 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS", NVTX_GPU);
3830
3831 /* Check quantity flags... */
3832 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3833 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3834
3835 /* Loop over particles... */
3836 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3837
3838 /* Get surface pressure... */
3839 double ps;
3841 INTPOL_2D(ps, 1);
3842
3843 /* Check whether particle is above the surface layer... */
3844 if (atm->p[ip] < ps - ctl->dry_depo_dp)
3845 continue;
3846
3847 /* Set depth of surface layer... */
3848 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
3849
3850 /* Calculate sedimentation velocity for particles... */
3851 double v_dep;
3852 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
3853
3854 /* Get temperature... */
3855 double t;
3856 INTPOL_3D(t, 1);
3857
3858 /* Set deposition velocity... */
3859 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3860 atm->q[ctl->qnt_rhop][ip]);
3861 }
3862
3863 /* Use explicit sedimentation velocity for gases... */
3864 else
3865 v_dep = ctl->dry_depo_vdep;
3866
3867 /* Calculate loss of mass based on deposition velocity... */
3868 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3869 if (ctl->qnt_m >= 0) {
3870 if (ctl->qnt_mloss_dry >= 0)
3871 atm->q[ctl->qnt_mloss_dry][ip]
3872 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3873 atm->q[ctl->qnt_m][ip] *= aux;
3874 if (ctl->qnt_loss_rate >= 0)
3875 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3876 }
3877 if (ctl->qnt_vmr >= 0)
3878 atm->q[ctl->qnt_vmr][ip] *= aux;
3879 }
3880}
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:10971
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2304
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2301
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:3023
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2448
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:3026
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 3884 of file mptrac.c.

3890 {
3891
3892 /* Set timer... */
3893 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS", NVTX_GPU);
3894
3895 /* Check quantity flags... */
3896 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3897 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3898
3899 /* Parameter of SO2 correction... */
3900 const double a = 3.12541941e-06;
3901 const double b = -5.72532259e-01;
3902 const double low = pow(1. / a, 1. / b);
3903
3904 /* Loop over particles... */
3905 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3906
3907 /* Check whether particle is inside cloud... */
3908 double lwc, rwc;
3910 INTPOL_3D(lwc, 1);
3911 INTPOL_3D(rwc, 0);
3912 if (!(lwc > 0 || rwc > 0))
3913 continue;
3914
3915 /* Get temperature... */
3916 double t;
3917 INTPOL_3D(t, 0);
3918
3919 /* Get molecular density... */
3920 const double M = MOLEC_DENS(atm->p[ip], t);
3921
3922 /* Reaction rate (Berglen et al., 2004)... */
3923 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3924
3925 /* Henry constant of SO2... */
3926 const double H_SO2 =
3927 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3928 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3929
3930 /* Henry constant of H2O2... */
3931 const double H_h2o2 =
3932 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3933
3934 /* Correction factor for high SO2 concentration
3935 (if qnt_Cx is defined, the correction is switched on)... */
3936 double cor = 1.0;
3937 if (ctl->qnt_Cx >= 0)
3938 cor = atm->q[ctl->qnt_Cx][ip] >
3939 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3940
3941 const double h2o2 = H_h2o2
3942 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3943 * M * cor * 1000. / AVO; /* unit: mol/L */
3944
3945 /* Volume water content in cloud [m^3 m^(-3)]... */
3946 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3947 const double CWC = (lwc + rwc) * rho_air / 1e3;
3948
3949 /* Calculate exponential decay (Rolph et al., 1992)... */
3950 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3951 const double aux = exp(-cache->dt[ip] * rate_coef);
3952 if (ctl->qnt_m >= 0) {
3953 if (ctl->qnt_mloss_h2o2 >= 0)
3954 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3955 atm->q[ctl->qnt_m][ip] *= aux;
3956 if (ctl->qnt_loss_rate >= 0)
3957 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3958 }
3959 if (ctl->qnt_vmr >= 0)
3960 atm->q[ctl->qnt_vmr][ip] *= aux;
3961 }
3962}
#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:2439
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 3966 of file mptrac.c.

3971 {
3972
3973 double t;
3974
3975 /* Set timer... */
3976 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS", NVTX_GPU);
3977
3978 /* Save pressure... */
3979 if (ctl->isosurf == 1) {
3980 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3981 cache->iso_var[ip] = atm->p[ip];
3982 }
3983 }
3984
3985 /* Save density... */
3986 else if (ctl->isosurf == 2) {
3987 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3989 INTPOL_3D(t, 1);
3990 cache->iso_var[ip] = atm->p[ip] / t;
3991 }
3992 }
3993
3994 /* Save potential temperature... */
3995 else if (ctl->isosurf == 3) {
3996 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3998 INTPOL_3D(t, 1);
3999 cache->iso_var[ip] = THETA(atm->p[ip], t);
4000 }
4001 }
4002
4003 /* Read balloon pressure data... */
4004 else if (ctl->isosurf == 4) {
4005
4006 /* Write info... */
4007 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
4008
4009 /* Open file... */
4010 FILE *in;
4011 if (!(in = fopen(ctl->balloon, "r")))
4012 ERRMSG("Cannot open file!");
4013
4014 /* Read pressure time series... */
4015 char line[LEN];
4016 while (fgets(line, LEN, in))
4017 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
4018 &(cache->iso_ps[cache->iso_n])) == 2)
4019 if ((++cache->iso_n) > NP)
4020 ERRMSG("Too many data points!");
4021
4022 /* Check number of points... */
4023 if (cache->iso_n < 1)
4024 ERRMSG("Could not read any data!");
4025
4026 /* Close file... */
4027 fclose(in);
4028
4029 /* Update of cache data on device... */
4030 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4031 }
4032}
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:6614
#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:3356
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3359
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3353
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3350
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2770
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2767
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 4036 of file mptrac.c.

4041 {
4042
4043 /* Set timer... */
4044 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
4045
4046 /* Loop over particles... */
4047 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4048
4049 /* Init... */
4050 double t;
4052
4053 /* Restore pressure... */
4054 if (ctl->isosurf == 1)
4055 atm->p[ip] = cache->iso_var[ip];
4056
4057 /* Restore density... */
4058 else if (ctl->isosurf == 2) {
4059 INTPOL_3D(t, 1);
4060 atm->p[ip] = cache->iso_var[ip] * t;
4061 }
4062
4063 /* Restore potential temperature... */
4064 else if (ctl->isosurf == 3) {
4065 INTPOL_3D(t, 1);
4066 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
4067 }
4068
4069 /* Interpolate pressure... */
4070 else if (ctl->isosurf == 4) {
4071 if (atm->time[ip] <= cache->iso_ts[0])
4072 atm->p[ip] = cache->iso_ps[0];
4073 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
4074 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
4075 else {
4076 const int idx =
4077 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
4078 atm->p[ip] =
4079 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
4080 cache->iso_ps[idx + 1], atm->time[ip]);
4081 }
4082 }
4083 }
4084}
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 4142 of file mptrac.c.

4148 {
4149
4150 /* Set timer... */
4151 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
4152
4153 /* Check quantity flags... */
4154 if (ctl->qnt_tsts >= 0)
4155 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
4156 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
4157
4158 /* Loop over particles... */
4159 PARTICLE_LOOP(0, atm->np, 0,
4160 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4161
4162 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
4163 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
4164 o3, lwc, rwc, iwc, swc, cc, z, zt;
4165
4166 /* Interpolate meteo data... */
4168 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
4169
4170 /* Set quantities... */
4171 SET_ATM(qnt_ps, ps);
4172 SET_ATM(qnt_ts, ts);
4173 SET_ATM(qnt_zs, zs);
4174 SET_ATM(qnt_us, us);
4175 SET_ATM(qnt_vs, vs);
4176 SET_ATM(qnt_ess, ess);
4177 SET_ATM(qnt_nss, nss);
4178 SET_ATM(qnt_shf, shf);
4179 SET_ATM(qnt_lsm, lsm);
4180 SET_ATM(qnt_sst, sst);
4181 SET_ATM(qnt_pbl, pbl);
4182 SET_ATM(qnt_pt, pt);
4183 SET_ATM(qnt_tt, tt);
4184 SET_ATM(qnt_zt, zt);
4185 SET_ATM(qnt_h2ot, h2ot);
4186 SET_ATM(qnt_zg, z);
4187 SET_ATM(qnt_p, atm->p[ip]);
4188 SET_ATM(qnt_t, t);
4189 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
4190 SET_ATM(qnt_u, u);
4191 SET_ATM(qnt_v, v);
4192 SET_ATM(qnt_w, w);
4193 SET_ATM(qnt_h2o, h2o);
4194 SET_ATM(qnt_o3, o3);
4195 SET_ATM(qnt_lwc, lwc);
4196 SET_ATM(qnt_rwc, rwc);
4197 SET_ATM(qnt_iwc, iwc);
4198 SET_ATM(qnt_swc, swc);
4199 SET_ATM(qnt_cc, cc);
4200 SET_ATM(qnt_pct, pct);
4201 SET_ATM(qnt_pcb, pcb);
4202 SET_ATM(qnt_cl, cl);
4203 SET_ATM(qnt_plcl, plcl);
4204 SET_ATM(qnt_plfc, plfc);
4205 SET_ATM(qnt_pel, pel);
4206 SET_ATM(qnt_cape, cape);
4207 SET_ATM(qnt_cin, cin);
4208 SET_ATM(qnt_o3c, o3c);
4209 SET_ATM(qnt_hno3,
4210 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
4211 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
4212 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4213 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
4214 atm->lat[ip], atm->p[ip]));
4215 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
4216 atm->lat[ip], atm->p[ip]));
4217 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
4218 atm->lat[ip], atm->p[ip]));
4219 SET_ATM(qnt_vh, sqrt(u * u + v * v));
4220 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
4221 SET_ATM(qnt_psat, PSAT(t));
4222 SET_ATM(qnt_psice, PSICE(t));
4223 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
4224 SET_ATM(qnt_sh, SH(h2o));
4225 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
4226 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
4227 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
4228 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
4229 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
4230 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
4231 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
4232 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
4233 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
4234 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
4235 SET_ATM(qnt_pv, pv);
4236 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
4237 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
4238 SET_ATM(qnt_tnat,
4239 nat_temperature(atm->p[ip], h2o,
4240 clim_zm(&clim->hno3, atm->time[ip],
4241 atm->lat[ip], atm->p[ip])));
4242 SET_ATM(qnt_tsts,
4243 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
4244 }
4245}
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:6921
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:2594
#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:3508
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2517
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2490
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2511
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2484
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2514
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 4249 of file mptrac.c.

4253 {
4254
4255 /* Set timer... */
4256 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
4257
4258 /* Allocate... */
4259 const int np = atm->np;
4260 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
4261 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
4262 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
4263
4264 /* Set grid box size... */
4265 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
4266 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
4267 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
4268
4269 /* Set time interval... */
4270 const double t0 = t - 0.5 * ctl->dt_mod;
4271 const double t1 = t + 0.5 * ctl->dt_mod;
4272
4273 /* Get indices... */
4274#ifdef _OPENACC
4275#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
4276#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
4277#pragma acc parallel loop independent gang vector
4278#else
4279#pragma omp parallel for default(shared)
4280#endif
4281 for (int ip = 0; ip < np; ip++) {
4282 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
4283 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
4284 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
4285 if (atm->time[ip] < t0 || atm->time[ip] > t1
4286 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
4287 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
4288 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
4289 izs[ip] = -1;
4290 }
4291
4292 /* Calculate interparcel mixing... */
4293 const int use_ensemble = (ctl->nens > 0);
4294
4295 const int quantities[] = {
4296 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
4297 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
4298 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
4299 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
4300 ctl->qnt_Csf6, ctl->qnt_aoa
4301 };
4302 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
4303
4304 for (int i = 0; i < n_qnt; i++)
4305 if (quantities[i] >= 0)
4306 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
4307 use_ensemble);
4308
4309 /* Free... */
4310#ifdef _OPENACC
4311#pragma acc exit data delete(ixs,iys,izs)
4312#endif
4313 free(ixs);
4314 free(iys);
4315 free(izs);
4316}
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:4320
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2532
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2927
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2924
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2544
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2921
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2529
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2936
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2535
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2939
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2538
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2918
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2930
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2942
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2547
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2541
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2933
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 4320 of file mptrac.c.

4328 {
4329
4330 const int np = atm->np;
4331 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
4332 const int nens = use_ensemble ? ctl->nens : 1;
4333 const int total_grid = ngrid * nens;
4334
4335 double *restrict const cmean =
4336 (double *) malloc((size_t) total_grid * sizeof(double));
4337 int *restrict const count =
4338 (int *) malloc((size_t) total_grid * sizeof(int));
4339
4340 /* Init... */
4341#ifdef _OPENACC
4342#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
4343#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
4344#pragma acc parallel loop independent gang vector
4345#else
4346#ifdef __NVCOMPILER
4347#pragma novector
4348#endif
4349#pragma omp parallel for
4350#endif
4351 for (int i = 0; i < total_grid; i++) {
4352 count[i] = 0;
4353 cmean[i] = 0.0;
4354 }
4355
4356 /* Loop over particles... */
4357#ifdef _OPENACC
4358#pragma acc parallel loop independent gang vector
4359#endif
4360 for (int ip = 0; ip < np; ip++)
4361 if (izs[ip] >= 0) {
4362 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4363 const int idx =
4364 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4365 ctl->mixing_nz);
4366#ifdef _OPENACC
4367#pragma acc atomic update
4368#endif
4369 cmean[idx] += atm->q[qnt_idx][ip];
4370#ifdef _OPENACC
4371#pragma acc atomic update
4372#endif
4373 count[idx]++;
4374 }
4375
4376 /* Compute means... */
4377#ifdef _OPENACC
4378#pragma acc parallel loop independent gang vector
4379#else
4380#ifdef __NVCOMPILER
4381#pragma novector
4382#endif
4383#pragma omp parallel for
4384#endif
4385 for (int i = 0; i < total_grid; i++)
4386 if (count[i] > 0)
4387 cmean[i] /= count[i];
4388
4389 /* Interparcel mixing... */
4390#ifdef _OPENACC
4391#pragma acc parallel loop independent gang vector
4392#else
4393#pragma omp parallel for
4394#endif
4395 for (int ip = 0; ip < np; ip++) {
4396 if (izs[ip] >= 0) {
4397 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4398
4399 double mixparam = 1.0;
4400 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
4401 const double w = tropo_weight(clim, atm, ip);
4402 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
4403 }
4404
4405 const int idx =
4406 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4407 ctl->mixing_nz);
4408 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
4409 }
4410 }
4411
4412 /* Free... */
4413#ifdef _OPENACC
4414#pragma acc exit data delete(cmean,count)
4415#endif
4416 free(cmean);
4417 free(count);
4418}
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2912
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2915
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 4422 of file mptrac.c.

4428 {
4429
4430 /* Set timer... */
4431 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS", NVTX_GPU);
4432
4433 /* Check quantity flags... */
4434 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4435 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4436
4437 /* Parameter of SO2 correction... */
4438 const double a = 4.71572206e-08;
4439 const double b = -8.28782867e-01;
4440 const double low = pow(1. / a, 1. / b);
4441
4442 /* Loop over particles... */
4443 PARTICLE_LOOP(0, atm->np, 1,
4444 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4445
4446 /* Get temperature... */
4447 double t;
4449 INTPOL_3D(t, 1);
4450
4451 /* Calculate molecular density... */
4452 const double M = MOLEC_DENS(atm->p[ip], t);
4453
4454 /* Use constant reaction rate... */
4455 double k = NAN;
4456 if (ctl->oh_chem_reaction == 1)
4457 k = ctl->oh_chem[0];
4458
4459 /* Calculate bimolecular reaction rate... */
4460 else if (ctl->oh_chem_reaction == 2)
4461 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
4462
4463 /* Calculate termolecular reaction rate... */
4464 if (ctl->oh_chem_reaction == 3) {
4465
4466 /* Calculate rate coefficient for X + OH + M -> XOH + M
4467 (JPL Publication 19-05) ... */
4468 const double k0 =
4469 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
4470 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
4471 const double ki =
4472 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
4473 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
4474 const double c = log10(k0 * M / ki);
4475 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
4476 }
4477
4478 /* Correction factor for high SO2 concentration
4479 (if qnt_Cx is defined, the correction is switched on)... */
4480 double cor = 1;
4481 if (ctl->qnt_Cx >= 0)
4482 cor =
4483 atm->q[ctl->qnt_Cx][ip] >
4484 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
4485
4486 /* Calculate exponential decay... */
4487 const double rate_coef =
4488 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
4489 atm->lat[ip], atm->p[ip]) * M * cor;
4490 const double aux = exp(-cache->dt[ip] * rate_coef);
4491 if (ctl->qnt_m >= 0) {
4492 if (ctl->qnt_mloss_oh >= 0)
4493 atm->q[ctl->qnt_mloss_oh][ip]
4494 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4495 atm->q[ctl->qnt_m][ip] *= aux;
4496 if (ctl->qnt_loss_rate >= 0)
4497 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4498 }
4499 if (ctl->qnt_vmr >= 0)
4500 atm->q[ctl->qnt_vmr][ip] *= aux;
4501 }
4502}
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2975
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2972
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2436
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 4506 of file mptrac.c.

4510 {
4511
4512 /* Set timer... */
4513 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
4514
4515 /* Loop over particles... */
4516 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
4517
4518 /* Init... */
4519 double ps;
4521
4522 /* Calculate modulo... */
4523 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
4524 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
4525
4526 /* Check latitude... */
4527 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
4528 if (atm->lat[ip] > 90) {
4529 atm->lat[ip] = 180 - atm->lat[ip];
4530 atm->lon[ip] += 180;
4531 }
4532 if (atm->lat[ip] < -90) {
4533 atm->lat[ip] = -180 - atm->lat[ip];
4534 atm->lon[ip] += 180;
4535 }
4536 }
4537
4538 /* Check longitude... */
4539 while (atm->lon[ip] < -180)
4540 atm->lon[ip] += 360;
4541 while (atm->lon[ip] >= 180)
4542 atm->lon[ip] -= 360;
4543
4544 /* Check pressure... */
4545 if (atm->p[ip] < met0->p[met0->np - 1]) {
4546 atm->p[ip] = met0->p[met0->np - 1];
4547 } else if (atm->p[ip] > 300.) {
4548 INTPOL_2D(ps, 1);
4549 if (atm->p[ip] > ps)
4550 atm->p[ip] = ps;
4551 }
4552 }
4553}

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

4558 {
4559
4560 /* Initialize GSL random number generators... */
4561 gsl_rng_env_setup();
4562 if (omp_get_max_threads() > NTHREADS)
4563 ERRMSG("Too many threads!");
4564 for (int i = 0; i < NTHREADS; i++) {
4565 rng[i] = gsl_rng_alloc(gsl_rng_default);
4566 gsl_rng_set(rng[i], gsl_rng_default_seed
4567 + (long unsigned) (ntask * NTHREADS + i));
4568 }
4569
4570 /* Initialize cuRAND random number generators... */
4571#ifdef CURAND
4572 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
4573 CURAND_STATUS_SUCCESS)
4574 ERRMSG("Cannot create random number generator!");
4575 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
4576 CURAND_STATUS_SUCCESS)
4577 ERRMSG("Cannot set seed for random number generator!");
4578 if (curandSetStream
4579 (rng_curand,
4580 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
4581 CURAND_STATUS_SUCCESS)
4582 ERRMSG("Cannot set stream for random number generator!");
4583#endif
4584}
#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 4588 of file mptrac.c.

4592 {
4593
4594 /* Use GSL random number generators... */
4595 if (ctl->rng_type == 0) {
4596
4597 /* Uniform distribution... */
4598 if (method == 0) {
4599#pragma omp parallel for default(shared)
4600 for (size_t i = 0; i < n; ++i)
4601 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
4602 }
4603
4604 /* Normal distribution... */
4605 else if (method == 1) {
4606#pragma omp parallel for default(shared)
4607 for (size_t i = 0; i < n; ++i)
4608 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
4609 }
4610
4611 /* Update of random numbers on device... */
4612#ifdef _OPENACC
4613 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
4614#pragma acc update device(rs[:n])
4615#endif
4616 }
4617
4618 /* Use Squares random number generator (Widynski, 2022)... */
4619 else if (ctl->rng_type == 1) {
4620
4621 /* Set key (don't change this!)... */
4622 const uint64_t key = 0xc8e4fd154ce32f6d;
4623
4624 /* Uniform distribution... */
4625#ifdef _OPENACC
4626#pragma acc data present(rs)
4627#pragma acc parallel loop independent gang vector
4628#else
4629#pragma omp parallel for default(shared)
4630#endif
4631 for (size_t i = 0; i < n + 1; ++i) {
4632 uint64_t r, t, x, y, z;
4633 y = x = (rng_ctr + i) * key;
4634 z = y + key;
4635 x = x * x + y;
4636 x = (x >> 32) | (x << 32);
4637 x = x * x + z;
4638 x = (x >> 32) | (x << 32);
4639 x = x * x + y;
4640 x = (x >> 32) | (x << 32);
4641 t = x = x * x + z;
4642 x = (x >> 32) | (x << 32);
4643 r = t ^ ((x * x + y) >> 32);
4644 rs[i] = (double) r / (double) UINT64_MAX;
4645 }
4646 rng_ctr += n + 1;
4647
4648 /* Normal distribution... */
4649 if (method == 1) {
4650#ifdef _OPENACC
4651#pragma acc parallel loop independent gang vector
4652#else
4653#pragma omp parallel for default(shared)
4654#endif
4655 for (size_t i = 0; i < n; i += 2) {
4656 const double r = sqrt(-2.0 * log(rs[i]));
4657 const double phi = 2.0 * M_PI * rs[i + 1];
4658 rs[i] = r * cosf((float) phi);
4659 rs[i + 1] = r * sinf((float) phi);
4660 }
4661 }
4662 }
4663
4664 /* Use cuRAND random number generators... */
4665 else if (ctl->rng_type == 2) {
4666#ifdef CURAND
4667#pragma acc host_data use_device(rs)
4668 {
4669
4670 /* Uniform distribution... */
4671 if (method == 0) {
4672 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
4673 CURAND_STATUS_SUCCESS)
4674 ERRMSG("Cannot create random numbers!");
4675 }
4676
4677 /* Normal distribution... */
4678 else if (method == 1) {
4679 if (curandGenerateNormalDouble
4680 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
4681 1.0) != CURAND_STATUS_SUCCESS)
4682 ERRMSG("Cannot create random numbers!");
4683 }
4684 }
4685#else
4686 ERRMSG("MPTRAC was compiled without cuRAND!");
4687#endif
4688 }
4689}
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2780

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

4698 {
4699
4700 /* Set timer... */
4701 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
4702
4703 /* Loop over particles... */
4704 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4705
4706 /* Get temperature... */
4707 double t;
4709 INTPOL_3D(t, 1);
4710
4711 /* Sedimentation velocity... */
4712 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4713 atm->q[ctl->qnt_rhop][ip]);
4714
4715 /* Calculate pressure change... */
4716 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
4717 }
4718}
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 4722 of file mptrac.c.

4725 {
4726
4727 /* Set timer... */
4728 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
4729
4730 /* Allocate... */
4731 const int np = atm->np;
4732 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
4733 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
4734 if (a == NULL || p == NULL)
4735 ERRMSG("Out of memory!");
4736
4737#ifdef _OPENACC
4738#pragma acc enter data create(a[0:np],p[0:np])
4739#pragma acc data present(ctl,met0,atm,a,p)
4740#endif
4741
4742 /* Get box index... */
4743#ifdef _OPENACC
4744#pragma acc parallel loop independent gang vector
4745#else
4746#pragma omp parallel for default(shared)
4747#endif
4748 for (int ip = 0; ip < np; ip++) {
4749 a[ip] =
4750 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
4751 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
4752 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
4753 p[ip] = ip;
4754 }
4755
4756 /* Sorting... */
4757#ifdef THRUST
4758#ifdef _OPENACC
4759#pragma acc host_data use_device(a,p)
4760#endif
4761 thrustSortWrapper(a, np, p);
4762#else
4763#ifdef _OPENACC
4764 ERRMSG("GSL sort fallback not available on GPU, use THRUST!");
4765#endif
4766 gsl_sort_index((size_t *) p, a, 1, (size_t) np);
4767#endif
4768
4769 /* Sort data... */
4770 module_sort_help(atm->time, p, np);
4771 module_sort_help(atm->p, p, np);
4772 module_sort_help(atm->lon, p, np);
4773 module_sort_help(atm->lat, p, np);
4774 for (int iq = 0; iq < ctl->nq; iq++)
4775 module_sort_help(atm->q[iq], p, np);
4776
4777 /* Free... */
4778#ifdef _OPENACC
4779#pragma acc exit data delete(a,p)
4780#endif
4781 free(a);
4782 free(p);
4783}
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:4787
int nq
Number of quantities.
Definition: mptrac.h:2271
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 4787 of file mptrac.c.

4790 {
4791
4792 /* Allocate... */
4793 double *restrict const help =
4794 (double *) malloc((size_t) np * sizeof(double));
4795 if (help == NULL)
4796 ERRMSG("Out of memory!");
4797
4798 /* Reordering of array... */
4799#ifdef _OPENACC
4800#pragma acc enter data create(help[0:np])
4801#pragma acc data present(a,p,help)
4802#pragma acc parallel loop independent gang vector
4803#else
4804#pragma omp parallel for default(shared)
4805#endif
4806 for (int ip = 0; ip < np; ip++)
4807 help[ip] = a[p[ip]];
4808#ifdef _OPENACC
4809#pragma acc parallel loop independent gang vector
4810#else
4811#pragma omp parallel for default(shared)
4812#endif
4813 for (int ip = 0; ip < np; ip++)
4814 a[ip] = help[ip];
4815
4816 /* Free... */
4817#ifdef _OPENACC
4818#pragma acc exit data delete(help)
4819#endif
4820 free(help);
4821}

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

4830 {
4831
4832 /* Set timer... */
4833 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
4834
4835 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
4836 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
4837
4838 const int local =
4839 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
4840
4841 /* Loop over particles... */
4842 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
4843
4844 /* Set time step for each air parcel... */
4845 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
4846 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
4847 && ctl->direction * (atm->time[ip] - t) < 0))
4848 cache->dt[ip] = t - atm->time[ip];
4849 else
4850 cache->dt[ip] = 0.0;
4851
4852 /* Check horizontal boundaries of local meteo data... */
4853#ifndef DD
4854 int dd = 1;
4855#else
4856 int dd = 0;
4857#endif
4858 if (dd) {
4859 if (local && (atm->lon[ip] <= met0->lon[0]
4860 || atm->lon[ip] >= met0->lon[met0->nx - 1]
4861 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
4862 cache->dt[ip] = 0.0;
4863 } else {
4864 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
4865 cache->dt[ip] = 0;
4866 }
4867 }
4868}
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2574
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2580
int qnt_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2568
double t_start
Start time of simulation [s].
Definition: mptrac.h:2577

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

4874 {
4875
4876 /* Set timer... */
4877 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS", NVTX_GPU);
4878
4879 /* Set start time... */
4880 if (ctl->direction == 1) {
4881 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4882 if (ctl->t_stop > 1e99)
4883 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4884 } else {
4885 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4886 if (ctl->t_stop > 1e99)
4887 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4888 }
4889
4890 /* Check time interval... */
4891 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4892 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4893
4894 /* Round start time... */
4895 if (ctl->direction == 1)
4896 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4897 else
4898 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4899}

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

4909 {
4910
4911 /* Set timer... */
4912 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS", NVTX_GPU);
4913
4914 /* Loop over particles... */
4915 PARTICLE_LOOP(0, atm->np, 1,
4916 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4917
4918 /* Get temperature... */
4919 double t;
4921 INTPOL_3D(t, 1);
4922
4923 /* Get molecular density... */
4924 const double M = MOLEC_DENS(atm->p[ip], t);
4925
4926 /* Get total column ozone... */
4927 double o3c;
4928 INTPOL_2D(o3c, 1);
4929
4930 /* Get solar zenith angle... */
4931 const double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
4932
4933 /* Get O(1D) volume mixing ratio... */
4934 const double o1d =
4935 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4936
4937 /* Reactions for CFC-10... */
4938 if (ctl->qnt_Cccl4 >= 0) {
4939 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4940 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4941 atm->p[ip], sza, o3c);
4942 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4943 }
4944
4945 /* Reactions for CFC-11... */
4946 if (ctl->qnt_Cccl3f >= 0) {
4947 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4948 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4949 atm->p[ip], sza, o3c);
4950 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4951 }
4952
4953 /* Reactions for CFC-12... */
4954 if (ctl->qnt_Cccl2f2 >= 0) {
4955 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4956 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4957 atm->p[ip], sza, o3c);
4958 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4959 }
4960
4961 /* Reactions for N2O... */
4962 if (ctl->qnt_Cn2o >= 0) {
4963 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4964 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4965 atm->p[ip], sza, o3c);
4966 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4967 }
4968 }
4969}
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:148
#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:3409
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3406
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3400
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3403
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3505
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 4973 of file mptrac.c.

4978 {
4979
4980 /* Set timer... */
4981 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS", NVTX_GPU);
4982
4983 /* Check quantity flags... */
4984 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4985 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4986
4987 /* Loop over particles... */
4988 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4989
4990 /* Check whether particle is below cloud top... */
4991 double pct;
4993 INTPOL_2D(pct, 1);
4994 if (!isfinite(pct) || atm->p[ip] <= pct)
4995 continue;
4996
4997 /* Get cloud bottom pressure... */
4998 double pcb;
4999 INTPOL_2D(pcb, 0);
5000
5001 /* Estimate precipitation rate (Pisso et al., 2019)... */
5002 double cl;
5003 INTPOL_2D(cl, 0);
5004 const double Is =
5005 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
5006 if (Is < 0.01)
5007 continue;
5008
5009 /* Check whether particle is inside or below cloud... */
5010 double lwc, rwc, iwc, swc;
5011 INTPOL_3D(lwc, 1);
5012 INTPOL_3D(rwc, 0);
5013 INTPOL_3D(iwc, 0);
5014 INTPOL_3D(swc, 0);
5015 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
5016
5017 /* Get temperature... */
5018 double t;
5019 INTPOL_3D(t, 0);
5020
5021 /* Calculate in-cloud scavenging coefficient... */
5022 double lambda = 0;
5023 if (inside) {
5024
5025 /* Calculate retention factor... */
5026 double eta;
5027 if (t > 273.15)
5028 eta = 1;
5029 else if (t <= 238.15)
5030 eta = ctl->wet_depo_ic_ret_ratio;
5031 else
5032 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
5033
5034 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5035 if (ctl->wet_depo_ic_a > 0)
5036 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
5037
5038 /* Use Henry's law for gases... */
5039 else if (ctl->wet_depo_ic_h[0] > 0) {
5040
5041 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5042 double h = ctl->wet_depo_ic_h[0]
5043 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
5044
5045 /* Use effective Henry's constant for SO2
5046 (Berglen, 2004; Simpson, 2012)... */
5047 if (ctl->wet_depo_so2_ph > 0) {
5048 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
5049 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
5050 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
5051 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
5052 }
5053
5054 /* Estimate depth of cloud layer... */
5055 const double dz = 1e3 * (Z(pct) - Z(pcb));
5056
5057 /* Calculate scavenging coefficient... */
5058 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5059 }
5060 }
5061
5062 /* Calculate below-cloud scavenging coefficient... */
5063 else {
5064
5065 /* Calculate retention factor... */
5066 double eta;
5067 if (t > 270)
5068 eta = 1;
5069 else
5070 eta = ctl->wet_depo_bc_ret_ratio;
5071
5072 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5073 if (ctl->wet_depo_bc_a > 0)
5074 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
5075
5076 /* Use Henry's law for gases... */
5077 else if (ctl->wet_depo_bc_h[0] > 0) {
5078
5079 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5080 const double h = ctl->wet_depo_bc_h[0]
5081 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
5082
5083 /* Estimate depth of cloud layer... */
5084 const double dz = 1e3 * (Z(pct) - Z(pcb));
5085
5086 /* Calculate scavenging coefficient... */
5087 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5088 }
5089 }
5090
5091 /* Calculate exponential decay of mass... */
5092 const double aux = exp(-cache->dt[ip] * lambda);
5093 if (ctl->qnt_m >= 0) {
5094 if (ctl->qnt_mloss_wet >= 0)
5095 atm->q[ctl->qnt_mloss_wet][ip]
5096 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5097 atm->q[ctl->qnt_m][ip] *= aux;
5098 if (ctl->qnt_loss_rate >= 0)
5099 atm->q[ctl->qnt_loss_rate][ip] += lambda;
5100 }
5101 if (ctl->qnt_vmr >= 0)
5102 atm->q[ctl->qnt_vmr][ip] *= aux;
5103 }
5104}
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:3002
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2996
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2445
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:3014
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2993
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3011
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:3020
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3008
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:3017
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:3005
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2999

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

5115 {
5116
5117 /* Initialize GPU... */
5118#ifdef _OPENACC
5119 SELECT_TIMER("ACC_INIT", "INIT", NVTX_GPU);
5120 int rank = 0;
5121#ifdef MPI
5122 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5123#endif
5124 if (acc_get_num_devices(acc_device_nvidia) <= 0)
5125 ERRMSG("Not running on a GPU device!");
5126 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
5127 acc_device_nvidia);
5128 acc_device_t device_type = acc_get_device_type();
5129 acc_init(device_type);
5130#endif
5131
5132 /* Allocate... */
5133 SELECT_TIMER("ALLOC", "MEMORY", NVTX_CPU);
5134 ALLOC(*ctl, ctl_t, 1);
5135 ALLOC(*cache, cache_t, 1);
5136 ALLOC(*clim, clim_t, 1);
5137 ALLOC(*met0, met_t, 1);
5138 ALLOC(*met1, met_t, 1);
5139 ALLOC(*atm, atm_t, 1);
5140 ALLOC(*dd, dd_t, 1);
5141
5142 /* Create data region on GPU... */
5143#ifdef _OPENACC
5144 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY", NVTX_GPU);
5145 ctl_t *ctlup = *ctl;
5146 cache_t *cacheup = *cache;
5147 clim_t *climup = *clim;
5148 met_t *met0up = *met0;
5149 met_t *met1up = *met1;
5150 atm_t *atmup = *atm;
5151#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
5152#ifdef DD
5153 dd_t *ddup = *dd;
5154#pragma acc enter data create(ddup[:1])
5155#endif
5156#endif
5157}
Air parcel data.
Definition: mptrac.h:3292
Cache data structure.
Definition: mptrac.h:3347
Climatological data.
Definition: mptrac.h:3487
Control parameters.
Definition: mptrac.h:2264
Domain decomposition data structure.
Definition: mptrac.h:3720
Meteo data structure.
Definition: mptrac.h:3546

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

5168 {
5169
5170 /* Delete data region on GPU... */
5171#ifdef _OPENACC
5172 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY", NVTX_GPU);
5173#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
5174#endif
5175
5176 /* Free... */
5177 SELECT_TIMER("FREE", "MEMORY", NVTX_CPU);
5178 free(atm);
5179 free(ctl);
5180 free(cache);
5181 free(clim);
5182 free(met0);
5183 free(met1);
5184
5185 /* Free MPI datatype... */
5186#ifdef DD
5187 MPI_Type_free(&dd->MPI_Particle);
5188#endif
5189 free(dd);
5190}

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

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

5200 {
5201
5202 static int init;
5203
5204 met_t *mets;
5205
5206 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
5207
5208 /* Set timer... */
5209 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5210
5211 /* Init... */
5212 if (t == ctl->t_start || !init) {
5213 init = 1;
5214
5215 /* Read meteo data... */
5216 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
5217 ctl->metbase, ctl->dt_met, filename);
5218 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5219 ERRMSG("Cannot open file!");
5220
5221 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
5222 ctl->metbase, ctl->dt_met, filename);
5223 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5224 ERRMSG("Cannot open file!");
5225
5226 /* Update GPU... */
5227 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
5228 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5229
5230 /* Caching... */
5231 if (ctl->met_cache && t != ctl->t_stop) {
5232 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
5233 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
5234 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5235 LOG(1, "Caching: %s", cachefile);
5236 if (system(cmd) != 0)
5237 WARN("Caching command failed!");
5238 }
5239 }
5240
5241 /* Read new data for forward trajectories... */
5242 if (t > (*met1)->time) {
5243
5244 /* Pointer swap... */
5245 mets = *met1;
5246 *met1 = *met0;
5247 *met0 = mets;
5248
5249 /* Read new meteo data... */
5250 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
5251 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5252 ERRMSG("Cannot open file!");
5253
5254 /* Update GPU... */
5255 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
5256 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5257
5258 /* Caching... */
5259 if (ctl->met_cache && t != ctl->t_stop) {
5260 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
5261 cachefile);
5262 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5263 LOG(1, "Caching: %s", cachefile);
5264 if (system(cmd) != 0)
5265 WARN("Caching command failed!");
5266 }
5267 }
5268
5269 /* Read new data for backward trajectories... */
5270 if (t < (*met0)->time) {
5271
5272 /* Pointer swap... */
5273 mets = *met1;
5274 *met1 = *met0;
5275 *met0 = mets;
5276
5277 /* Read new meteo data... */
5278 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
5279 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5280 ERRMSG("Cannot open file!");
5281
5282 /* Update GPU... */
5283 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
5284 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5285
5286 /* Caching... */
5287 if (ctl->met_cache && t != ctl->t_stop) {
5288 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
5289 cachefile);
5290 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5291 LOG(1, "Caching: %s", cachefile);
5292 if (system(cmd) != 0)
5293 WARN("Caching command failed!");
5294 }
5295 }
5296
5297 /* Check that grids are consistent... */
5298 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
5299 if ((*met0)->nx != (*met1)->nx
5300 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
5301 ERRMSG("Meteo grid dimensions do not match!");
5302 for (int ix = 0; ix < (*met0)->nx; ix++)
5303 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
5304 ERRMSG("Meteo grid longitudes do not match!");
5305 for (int iy = 0; iy < (*met0)->ny; iy++)
5306 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
5307 ERRMSG("Meteo grid latitudes do not match!");
5308 for (int ip = 0; ip < (*met0)->np; ip++)
5309 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
5310 ERRMSG("Meteo grid pressure levels do not match!");
5311 }
5312}
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:1933
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:6357
#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:2753
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2590
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 5316 of file mptrac.c.

5321 {
5322
5323 /* Initialize timesteps... */
5324 module_timesteps_init(ctl, atm);
5325
5326 /* Initialize random number generator... */
5327 module_rng_init(ntask);
5328
5329 /* Update GPU memory... */
5330 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
5331}
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4872
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:4557
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 5335 of file mptrac.c.

5338 {
5339
5340 int result;
5341
5342 /* Set timer... */
5343 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
5344
5345 /* Init... */
5346 atm->np = 0;
5347
5348 /* Write info... */
5349 LOG(1, "Read atmospheric data: %s", filename);
5350
5351 /* Read ASCII data... */
5352 if (ctl->atm_type == 0)
5353 result = read_atm_asc(filename, ctl, atm);
5354
5355 /* Read binary data... */
5356 else if (ctl->atm_type == 1)
5357 result = read_atm_bin(filename, ctl, atm);
5358
5359 /* Read netCDF data... */
5360 else if (ctl->atm_type == 2)
5361 result = read_atm_nc(filename, ctl, atm);
5362
5363 /* Read CLaMS data... */
5364 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
5365 result = read_atm_clams(filename, ctl, atm);
5366
5367 /* Error... */
5368 else
5369 ERRMSG("Atmospheric data type not supported!");
5370
5371 /* Check result... */
5372 if (result != 1)
5373 return 0;
5374
5375 /* Check number of air parcels... */
5376 if (atm->np < 1)
5377 ERRMSG("Can not read any data!");
5378
5379 /* Write info... */
5380 double mini, maxi;
5381 LOG(2, "Number of particles: %d", atm->np);
5382 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5383 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5384 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5385 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5386 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5387 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5388 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5389 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5390 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5391 for (int iq = 0; iq < ctl->nq; iq++) {
5392 char msg[5 * LEN];
5393 sprintf(msg, "Quantity %s range: %s ... %s %s",
5394 ctl->qnt_name[iq], ctl->qnt_format[iq],
5395 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5396 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5397 LOG(2, msg, mini, maxi);
5398 }
5399
5400 /* Return success... */
5401 return 1;
5402}
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:7125
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:7009
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:7065
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:6967
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2283
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3055
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2280
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2274
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 5406 of file mptrac.c.

5408 {
5409
5410 /* Set timer... */
5411 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
5412
5413 /* Init tropopause climatology... */
5414 clim_tropo_init(clim);
5415
5416 /* Read photolysis rates... */
5417 if (ctl->clim_photo[0] != '-')
5418 read_clim_photo(ctl->clim_photo, &clim->photo);
5419
5420 /* Read HNO3 climatology... */
5421 if (ctl->clim_hno3_filename[0] != '-')
5422 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
5423
5424 /* Read OH climatology... */
5425 if (ctl->clim_oh_filename[0] != '-') {
5426 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
5427 if (ctl->oh_chem_beta > 0)
5428 clim_oh_diurnal_correction(ctl, clim);
5429 }
5430
5431 /* Read H2O2 climatology... */
5432 if (ctl->clim_h2o2_filename[0] != '-')
5433 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
5434
5435 /* Read HO2 climatology... */
5436 if (ctl->clim_ho2_filename[0] != '-')
5437 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
5438
5439 /* Read O(1D) climatology... */
5440 if (ctl->clim_o1d_filename[0] != '-')
5441 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
5442
5443 /* Read CFC-10 time series... */
5444 if (ctl->clim_ccl4_timeseries[0] != '-')
5446
5447 /* Read CFC-11 time series... */
5448 if (ctl->clim_ccl3f_timeseries[0] != '-')
5450
5451 /* Read CFC-12 time series... */
5452 if (ctl->clim_ccl2f2_timeseries[0] != '-')
5454
5455 /* Read N2O time series... */
5456 if (ctl->clim_n2o_timeseries[0] != '-')
5457 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
5458
5459 /* Read SF6 time series... */
5460 if (ctl->clim_sf6_timeseries[0] != '-')
5461 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
5462}
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:7158
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:7277
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:7331
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:233
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:2885
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2888
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2873
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2882
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2879
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2876
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 5466 of file mptrac.c.

5470 {
5471
5472 /* Set timer... */
5473 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
5474
5475 /* Write info... */
5476 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
5477 "(executable: %s | version: %s | compiled: %s, %s)\n",
5478 argv[0], VERSION, __DATE__, __TIME__);
5479
5480 /* Initialize quantity indices... */
5481 ctl->qnt_idx = -1;
5482 ctl->qnt_ens = -1;
5483 ctl->qnt_stat = -1;
5484 ctl->qnt_m = -1;
5485 ctl->qnt_vmr = -1;
5486 ctl->qnt_rp = -1;
5487 ctl->qnt_rhop = -1;
5488 ctl->qnt_ps = -1;
5489 ctl->qnt_ts = -1;
5490 ctl->qnt_zs = -1;
5491 ctl->qnt_us = -1;
5492 ctl->qnt_vs = -1;
5493 ctl->qnt_ess = -1;
5494 ctl->qnt_nss = -1;
5495 ctl->qnt_shf = -1;
5496 ctl->qnt_lsm = -1;
5497 ctl->qnt_sst = -1;
5498 ctl->qnt_pbl = -1;
5499 ctl->qnt_pt = -1;
5500 ctl->qnt_tt = -1;
5501 ctl->qnt_zt = -1;
5502 ctl->qnt_h2ot = -1;
5503 ctl->qnt_zg = -1;
5504 ctl->qnt_p = -1;
5505 ctl->qnt_t = -1;
5506 ctl->qnt_rho = -1;
5507 ctl->qnt_u = -1;
5508 ctl->qnt_v = -1;
5509 ctl->qnt_w = -1;
5510 ctl->qnt_h2o = -1;
5511 ctl->qnt_o3 = -1;
5512 ctl->qnt_lwc = -1;
5513 ctl->qnt_rwc = -1;
5514 ctl->qnt_iwc = -1;
5515 ctl->qnt_swc = -1;
5516 ctl->qnt_cc = -1;
5517 ctl->qnt_pct = -1;
5518 ctl->qnt_pcb = -1;
5519 ctl->qnt_cl = -1;
5520 ctl->qnt_plcl = -1;
5521 ctl->qnt_plfc = -1;
5522 ctl->qnt_pel = -1;
5523 ctl->qnt_cape = -1;
5524 ctl->qnt_cin = -1;
5525 ctl->qnt_o3c = -1;
5526 ctl->qnt_hno3 = -1;
5527 ctl->qnt_oh = -1;
5528 ctl->qnt_h2o2 = -1;
5529 ctl->qnt_ho2 = -1;
5530 ctl->qnt_o1d = -1;
5531 ctl->qnt_mloss_oh = -1;
5532 ctl->qnt_mloss_h2o2 = -1;
5533 ctl->qnt_mloss_kpp = -1;
5534 ctl->qnt_mloss_wet = -1;
5535 ctl->qnt_mloss_dry = -1;
5536 ctl->qnt_mloss_decay = -1;
5537 ctl->qnt_loss_rate = -1;
5538 ctl->qnt_psat = -1;
5539 ctl->qnt_psice = -1;
5540 ctl->qnt_pw = -1;
5541 ctl->qnt_sh = -1;
5542 ctl->qnt_rh = -1;
5543 ctl->qnt_rhice = -1;
5544 ctl->qnt_theta = -1;
5545 ctl->qnt_zeta = -1;
5546 ctl->qnt_zeta_d = -1;
5547 ctl->qnt_zeta_dot = -1;
5548 ctl->qnt_eta = -1;
5549 ctl->qnt_eta_dot = -1;
5550 ctl->qnt_tvirt = -1;
5551 ctl->qnt_lapse = -1;
5552 ctl->qnt_vh = -1;
5553 ctl->qnt_vz = -1;
5554 ctl->qnt_pv = -1;
5555 ctl->qnt_tdew = -1;
5556 ctl->qnt_tice = -1;
5557 ctl->qnt_tsts = -1;
5558 ctl->qnt_tnat = -1;
5559 ctl->qnt_Cx = -1;
5560 ctl->qnt_Ch2o = -1;
5561 ctl->qnt_Co3 = -1;
5562 ctl->qnt_Cco = -1;
5563 ctl->qnt_Coh = -1;
5564 ctl->qnt_Ch = -1;
5565 ctl->qnt_Cho2 = -1;
5566 ctl->qnt_Ch2o2 = -1;
5567 ctl->qnt_Co1d = -1;
5568 ctl->qnt_Co3p = -1;
5569 ctl->qnt_Cccl4 = -1;
5570 ctl->qnt_Cccl3f = -1;
5571 ctl->qnt_Cccl2f2 = -1;
5572 ctl->qnt_Cn2o = -1;
5573 ctl->qnt_Csf6 = -1;
5574 ctl->qnt_aoa = -1;
5575
5576#ifdef DD
5577 ctl->qnt_destination = -1;
5578 ctl->qnt_subdomain = -1;
5579#endif
5580
5581 /* Read quantities... */
5582 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
5583 if (ctl->nq > NQ)
5584 ERRMSG("Too many quantities!");
5585 for (int iq = 0; iq < ctl->nq; iq++) {
5586
5587 /* Read quantity name and format... */
5588 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
5589 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
5590 ctl->qnt_longname[iq]);
5591 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
5592 ctl->qnt_format[iq]);
5593 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
5594 sprintf(ctl->qnt_format[iq], "%%.2f");
5595
5596 /* Try to identify quantity... */
5597 SET_QNT(qnt_idx, "idx", "particle index", "-")
5598 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
5599 SET_QNT(qnt_stat, "stat", "station flag", "-")
5600 SET_QNT(qnt_m, "m", "mass", "kg")
5601 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
5602 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
5603 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
5604 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
5605 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
5606 SET_QNT(qnt_zs, "zs", "surface height", "km")
5607 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
5608 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
5609 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
5610 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
5611 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
5612 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
5613 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
5614 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
5615 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
5616 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
5617 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
5618 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
5619 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
5620 SET_QNT(qnt_p, "p", "pressure", "hPa")
5621 SET_QNT(qnt_t, "t", "temperature", "K")
5622 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
5623 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
5624 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
5625 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
5626 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
5627 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
5628 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
5629 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
5630 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
5631 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
5632 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
5633 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
5634 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
5635 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
5636 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
5637 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
5638 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
5639 SET_QNT(qnt_cape, "cape", "convective available potential energy",
5640 "J/kg")
5641 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
5642 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
5643 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
5644 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
5645 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
5646 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
5647 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
5648 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
5649 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
5650 "mass loss due to H2O2 chemistry", "kg")
5651 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
5652 "kg")
5653 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
5654 "kg")
5655 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
5656 "kg")
5657 SET_QNT(qnt_mloss_decay, "mloss_decay",
5658 "mass loss due to exponential decay", "kg")
5659 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
5660 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
5661 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
5662 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
5663 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
5664 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
5665 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
5666 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
5667 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
5668 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
5669 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
5670 "K/day")
5671 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
5672 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
5673 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
5674 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
5675 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
5676 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
5677 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
5678 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
5679 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
5680 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
5681 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
5682 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
5683 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
5684 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
5685 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
5686 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
5687 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
5688 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
5689 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
5690 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
5691 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
5692 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
5693 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
5694 "ppv")
5695 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
5696 "ppv")
5697 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
5698 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
5699 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
5700#ifdef DD
5701 SET_QNT(qnt_destination, "destination",
5702 "subdomain index of destination", "-")
5703 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
5704#endif
5705 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
5706 }
5707
5708 /* Vertical coordinate and velocity... */
5709 ctl->advect_vert_coord =
5710 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
5711 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
5712 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
5713
5714 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
5715 ERRMSG("Add quantity zeta for diabatic advection!");
5716 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
5717 ERRMSG("Add quantity eta for etadot avection!");
5718
5719 ctl->met_vert_coord =
5720 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
5721 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
5722 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
5723
5724 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
5725 ERRMSG
5726 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
5727 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
5728 ERRMSG
5729 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
5730
5731 /* Time steps of simulation... */
5732 ctl->direction =
5733 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
5734 if (ctl->direction != -1 && ctl->direction != 1)
5735 ERRMSG("Set DIRECTION to -1 or 1!");
5736 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
5737 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
5738
5739 /* Meteo data... */
5740 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
5741 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
5742 ctl->met_convention =
5743 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
5744 ctl->met_type =
5745 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
5746 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
5747 ERRMSG
5748 ("Please use meteo files in netcdf format for diabatic calculations.");
5749 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
5750 ERRMSG
5751 ("Please use meteo files in netcdf format for etadot calculations.");
5752 ctl->met_clams =
5753 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
5754 ctl->met_nc_scale =
5755 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
5756 ctl->met_nc_level =
5757 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
5758 ctl->met_nc_quant =
5759 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
5760 ctl->met_zstd_level =
5761 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
5762 for (int i = 0; i < METVAR; i++) {
5763 char defprec[LEN] = "0", deftol[LEN] = "0.0";
5764 if (i == 0) /* geopotential height */
5765 sprintf(deftol, "0.5");
5766 else if (i == 1) /* temperature */
5767 sprintf(deftol, "5.0");
5768 else /* other variables */
5769 sprintf(defprec, "8");
5770 ctl->met_comp_prec[i] =
5771 (int) scan_ctl(filename, argc, argv, "MET_COMP_PREC", i, defprec, NULL);
5772 ctl->met_comp_tol[i] =
5773 scan_ctl(filename, argc, argv, "MET_COMP_TOL", i, deftol, NULL);
5774 }
5775 ctl->met_cms_batch =
5776 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
5777 ctl->met_cms_zstd =
5778 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
5779 ctl->met_cms_heur =
5780 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
5781 ctl->met_cms_eps_z =
5782 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
5783 ctl->met_cms_eps_t =
5784 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
5785 ctl->met_cms_eps_u =
5786 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
5787 ctl->met_cms_eps_v =
5788 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
5789 ctl->met_cms_eps_w =
5790 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
5791 ctl->met_cms_eps_pv =
5792 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
5793 ctl->met_cms_eps_h2o =
5794 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
5795 ctl->met_cms_eps_o3 =
5796 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5797 ctl->met_cms_eps_lwc =
5798 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5799 ctl->met_cms_eps_rwc =
5800 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5801 ctl->met_cms_eps_iwc =
5802 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5803 ctl->met_cms_eps_swc =
5804 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5805 ctl->met_cms_eps_cc =
5806 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5807 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5808 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5809 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5810 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5811 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5812 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5813 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5814 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5815 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5816 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5817 ctl->met_detrend =
5818 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5819 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5820 if (ctl->met_np > EP)
5821 ERRMSG("Too many pressure levels!");
5822 ctl->met_press_level_def =
5823 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5824 NULL);
5825 if (ctl->met_press_level_def >= 0) {
5826 level_definitions(ctl);
5827 } else {
5828 if (ctl->met_np > 0) {
5829 for (int ip = 0; ip < ctl->met_np; ip++)
5830 ctl->met_p[ip] =
5831 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5832 }
5833 }
5834 ctl->met_nlev =
5835 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
5836 if (ctl->met_nlev > EP)
5837 ERRMSG("Too many model levels!");
5838 for (int ip = 0; ip < ctl->met_nlev; ip++)
5839 ctl->met_lev_hyam[ip] =
5840 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
5841 for (int ip = 0; ip < ctl->met_nlev; ip++)
5842 ctl->met_lev_hybm[ip] =
5843 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
5844 ctl->met_geopot_sx =
5845 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5846 ctl->met_geopot_sy =
5847 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5848 ctl->met_relhum =
5849 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5850 ctl->met_cape =
5851 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
5852 if (ctl->met_cape < 0 || ctl->met_cape > 1)
5853 ERRMSG("Set MET_CAPE to 0 or 1!");
5854 ctl->met_pbl =
5855 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
5856 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
5857 ERRMSG("Set MET_PBL to 0 ... 3!");
5858 ctl->met_pbl_min =
5859 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
5860 ctl->met_pbl_max =
5861 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
5862 ctl->met_tropo =
5863 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5864 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5865 ERRMSG("Set MET_TROPO to 0 ... 5!");
5866 ctl->met_tropo_pv =
5867 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5868 ctl->met_tropo_theta =
5869 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5870 ctl->met_tropo_spline =
5871 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5872 ctl->met_dt_out =
5873 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5874 ctl->met_cache =
5875 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5876 ctl->met_mpi_share =
5877 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5878
5879 /* Sorting... */
5880 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5881
5882 /* Isosurface parameters... */
5883 ctl->isosurf =
5884 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5885 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5886
5887 /* Random number generator... */
5888 ctl->rng_type =
5889 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
5890 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5891 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5892
5893 /* Advection parameters... */
5894 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
5895 if (!
5896 (ctl->advect == 0 || ctl->advect == 1 || ctl->advect == 2
5897 || ctl->advect == 4))
5898 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
5899
5900 /* Diffusion parameters... */
5901 ctl->diffusion
5902 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
5903 if (ctl->diffusion < 0 || ctl->diffusion > 2)
5904 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
5905 ctl->turb_dx_pbl =
5906 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
5907 ctl->turb_dx_trop =
5908 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5909 ctl->turb_dx_strat =
5910 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5911 ctl->turb_dz_pbl =
5912 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
5913 ctl->turb_dz_trop =
5914 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5915 ctl->turb_dz_strat =
5916 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5917 ctl->turb_mesox =
5918 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5919 ctl->turb_mesoz =
5920 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5921
5922 /* Convection... */
5923 ctl->conv_mix_pbl
5924 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5925 ctl->conv_pbl_trans
5926 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5927 ctl->conv_cape
5928 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5929 ctl->conv_cin
5930 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5931 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5932
5933 /* Boundary conditions... */
5934 ctl->bound_mass =
5935 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5936 ctl->bound_mass_trend =
5937 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5938 ctl->bound_vmr =
5939 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5940 ctl->bound_vmr_trend =
5941 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5942 ctl->bound_lat0 =
5943 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5944 ctl->bound_lat1 =
5945 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5946 ctl->bound_p0 =
5947 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5948 ctl->bound_p1 =
5949 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5950 ctl->bound_dps =
5951 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5952 ctl->bound_dzs =
5953 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5954 ctl->bound_zetas =
5955 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5956 ctl->bound_pbl =
5957 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5958
5959 /* Species parameters... */
5960 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5961 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5962 ctl->molmass = 120.907;
5963 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5964 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5965 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5966 ctl->molmass = 137.359;
5967 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5968 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5969 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5970 ctl->molmass = 16.043;
5971 ctl->oh_chem_reaction = 2;
5972 ctl->oh_chem[0] = 2.45e-12;
5973 ctl->oh_chem[1] = 1775;
5974 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5975 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5976 } else if (strcasecmp(ctl->species, "CO") == 0) {
5977 ctl->molmass = 28.01;
5978 ctl->oh_chem_reaction = 3;
5979 ctl->oh_chem[0] = 6.9e-33;
5980 ctl->oh_chem[1] = 2.1;
5981 ctl->oh_chem[2] = 1.1e-12;
5982 ctl->oh_chem[3] = -1.3;
5983 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5984 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5985 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5986 ctl->molmass = 44.009;
5987 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5988 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5989 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5990 ctl->molmass = 18.01528;
5991 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5992 ctl->molmass = 44.013;
5993 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5994 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5995 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5996 ctl->molmass = 17.031;
5997 ctl->oh_chem_reaction = 2;
5998 ctl->oh_chem[0] = 1.7e-12;
5999 ctl->oh_chem[1] = 710;
6000 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
6001 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
6002 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
6003 ctl->molmass = 63.012;
6004 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
6005 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
6006 } else if (strcasecmp(ctl->species, "NO") == 0) {
6007 ctl->molmass = 30.006;
6008 ctl->oh_chem_reaction = 3;
6009 ctl->oh_chem[0] = 7.1e-31;
6010 ctl->oh_chem[1] = 2.6;
6011 ctl->oh_chem[2] = 3.6e-11;
6012 ctl->oh_chem[3] = 0.1;
6013 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
6014 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6015 } else if (strcasecmp(ctl->species, "NO2") == 0) {
6016 ctl->molmass = 46.005;
6017 ctl->oh_chem_reaction = 3;
6018 ctl->oh_chem[0] = 1.8e-30;
6019 ctl->oh_chem[1] = 3.0;
6020 ctl->oh_chem[2] = 2.8e-11;
6021 ctl->oh_chem[3] = 0.0;
6022 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
6023 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6024 } else if (strcasecmp(ctl->species, "O3") == 0) {
6025 ctl->molmass = 47.997;
6026 ctl->oh_chem_reaction = 2;
6027 ctl->oh_chem[0] = 1.7e-12;
6028 ctl->oh_chem[1] = 940;
6029 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
6030 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
6031 } else if (strcasecmp(ctl->species, "SF6") == 0) {
6032 ctl->molmass = 146.048;
6033 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
6034 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
6035 } else if (strcasecmp(ctl->species, "SO2") == 0) {
6036 ctl->molmass = 64.066;
6037 ctl->oh_chem_reaction = 3;
6038 ctl->oh_chem[0] = 2.9e-31;
6039 ctl->oh_chem[1] = 4.1;
6040 ctl->oh_chem[2] = 1.7e-12;
6041 ctl->oh_chem[3] = -0.2;
6042 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
6043 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
6044 }
6045
6046 /* Molar mass... */
6047 char defstr[LEN];
6048 sprintf(defstr, "%g", ctl->molmass);
6049 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
6050
6051 /* OH chemistry... */
6052 sprintf(defstr, "%d", ctl->oh_chem_reaction);
6053 ctl->oh_chem_reaction =
6054 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
6055 NULL);
6056 for (int ip = 0; ip < 4; ip++) {
6057 sprintf(defstr, "%g", ctl->oh_chem[ip]);
6058 ctl->oh_chem[ip] =
6059 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
6060 }
6061 ctl->oh_chem_beta =
6062 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
6063
6064 /* H2O2 chemistry... */
6065 ctl->h2o2_chem_reaction =
6066 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
6067
6068 /* KPP chemistry... */
6069 ctl->kpp_chem =
6070 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
6071 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
6072
6073 /* First order tracer chemistry... */
6074 ctl->tracer_chem =
6075 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
6076
6077 /* Wet deposition... */
6078 for (int ip = 0; ip < 2; ip++) {
6079 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
6080 ctl->wet_depo_ic_h[ip] =
6081 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
6082 }
6083 for (int ip = 0; ip < 1; ip++) {
6084 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
6085 ctl->wet_depo_bc_h[ip] =
6086 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
6087 }
6088 ctl->wet_depo_so2_ph =
6089 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
6090 ctl->wet_depo_ic_a =
6091 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
6092 ctl->wet_depo_ic_b =
6093 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
6094 ctl->wet_depo_bc_a =
6095 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
6096 ctl->wet_depo_bc_b =
6097 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
6098 ctl->wet_depo_pre[0] =
6099 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
6100 ctl->wet_depo_pre[1] =
6101 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
6103 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
6105 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
6106
6107 /* Dry deposition... */
6108 ctl->dry_depo_vdep =
6109 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
6110 ctl->dry_depo_dp =
6111 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
6112
6113 /* Climatological data... */
6114 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
6115 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
6116 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
6117 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
6118 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
6119 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
6120 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
6121 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
6122 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
6123 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
6124 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
6125 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
6126 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
6127 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
6128 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
6129 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
6130 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
6131 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
6132 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
6133 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
6134 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
6135 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
6136
6137 /* Mixing... */
6138 ctl->mixing_dt =
6139 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
6140 ctl->mixing_trop =
6141 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
6142 ctl->mixing_strat =
6143 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
6144 ctl->mixing_z0 =
6145 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
6146 ctl->mixing_z1 =
6147 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
6148 ctl->mixing_nz =
6149 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
6150 ctl->mixing_lon0 =
6151 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
6152 ctl->mixing_lon1 =
6153 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
6154 ctl->mixing_nx =
6155 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
6156 ctl->mixing_lat0 =
6157 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
6158 ctl->mixing_lat1 =
6159 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
6160 ctl->mixing_ny =
6161 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
6162
6163 /* Chemistry grid... */
6164 ctl->chemgrid_z0 =
6165 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
6166 ctl->chemgrid_z1 =
6167 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
6168 ctl->chemgrid_nz =
6169 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
6170 ctl->chemgrid_lon0 =
6171 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
6172 ctl->chemgrid_lon1 =
6173 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
6174 ctl->chemgrid_nx =
6175 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
6176 ctl->chemgrid_lat0 =
6177 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
6178 ctl->chemgrid_lat1 =
6179 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
6180 ctl->chemgrid_ny =
6181 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
6182
6183 /* Exponential decay... */
6184 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
6185 ctl->tdec_strat =
6186 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
6187
6188 /* PSC analysis... */
6189 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
6190 ctl->psc_hno3 =
6191 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
6192
6193 /* Output of atmospheric data... */
6194 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
6195 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
6196 ctl->atm_dt_out =
6197 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
6198 ctl->atm_filter =
6199 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
6200 ctl->atm_stride =
6201 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
6202 ctl->atm_type =
6203 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
6204 ctl->atm_type_out =
6205 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
6206 if (ctl->atm_type_out == -1)
6207 ctl->atm_type_out = ctl->atm_type;
6208 ctl->atm_nc_level =
6209 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
6210 for (int iq = 0; iq < ctl->nq; iq++)
6211 ctl->atm_nc_quant[iq] =
6212 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
6213 ctl->obs_type =
6214 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
6215
6216 /* Output of CSI data... */
6217 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
6218 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
6219 ctl->csi_dt_out =
6220 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
6221 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
6222 ctl->csi_obsmin =
6223 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
6224 ctl->csi_modmin =
6225 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
6226 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
6227 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
6228 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
6229 ctl->csi_lon0 =
6230 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
6231 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
6232 ctl->csi_nx =
6233 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
6234 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
6235 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
6236 ctl->csi_ny =
6237 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
6238
6239 /* Output of ensemble data... */
6240 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
6241 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
6242 ctl->ens_dt_out =
6243 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
6244
6245 /* Output of grid data... */
6246 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
6247 ctl->grid_basename);
6248 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
6249 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
6250 ctl->grid_dt_out =
6251 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
6252 ctl->grid_sparse =
6253 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
6254 ctl->grid_nc_level =
6255 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
6256 for (int iq = 0; iq < ctl->nq; iq++)
6257 ctl->grid_nc_quant[iq] =
6258 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
6259 ctl->grid_stddev =
6260 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
6261 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
6262 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
6263 ctl->grid_nz =
6264 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
6265 ctl->grid_lon0 =
6266 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
6267 ctl->grid_lon1 =
6268 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
6269 ctl->grid_nx =
6270 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
6271 ctl->grid_lat0 =
6272 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
6273 ctl->grid_lat1 =
6274 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
6275 ctl->grid_ny =
6276 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
6277 ctl->grid_type =
6278 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
6279
6280 /* Output of profile data... */
6281 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
6282 ctl->prof_basename);
6283 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
6284 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
6285 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
6286 ctl->prof_nz =
6287 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
6288 ctl->prof_lon0 =
6289 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
6290 ctl->prof_lon1 =
6291 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
6292 ctl->prof_nx =
6293 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
6294 ctl->prof_lat0 =
6295 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
6296 ctl->prof_lat1 =
6297 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
6298 ctl->prof_ny =
6299 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
6300
6301 /* Output of sample data... */
6302 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
6303 ctl->sample_basename);
6304 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
6305 ctl->sample_kernel);
6306 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
6307 ctl->sample_obsfile);
6308 ctl->sample_dx =
6309 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
6310 ctl->sample_dz =
6311 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
6312
6313 /* Output of station data... */
6314 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
6315 ctl->stat_basename);
6316 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
6317 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
6318 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
6319 ctl->stat_t0 =
6320 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
6321 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
6322
6323 /* Output of VTK data... */
6324 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
6325 ctl->vtk_dt_out =
6326 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
6327 ctl->vtk_stride =
6328 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
6329 ctl->vtk_scale =
6330 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
6331 ctl->vtk_offset =
6332 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
6333 ctl->vtk_sphere =
6334 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
6335
6336 /* Domain decomposition... */
6337 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
6339 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
6340 (ctl->dd == 1) ? "2" : "1", NULL);
6341 ctl->dd_subdomains_zonal =
6342 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
6343 (ctl->dd == 1) ? "2" : "1", NULL);
6345 ctl->dd = 1;
6346 else if (ctl->dd == 1)
6347 ERRMSG("Please provide zonal and meridional subdomain numbers!")
6348 ctl->dd_nbr_neighbours =
6349 (int) scan_ctl(filename, argc, argv, "DD_NBR_NEIGHBOURS", -1, "8",
6350 NULL);
6351 ctl->dd_halos_size =
6352 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
6353}
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:2612
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:10899
#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:3153
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2376
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3114
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3081
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2610
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2409
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3090
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2355
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3042
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2388
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3084
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2397
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3105
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2364
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3231
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2763
double stat_r
Search radius around station [km].
Definition: mptrac.h:3237
int met_zstd_level
ZSTD compression level (from -5 to 22).
Definition: mptrac.h:2619
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3108
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3261
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2731
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2385
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2653
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2463
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3180
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3156
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2683
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2750
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2427
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2499
char species[LEN]
Species.
Definition: mptrac.h:2861
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3099
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3111
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2728
double met_comp_tol[METVAR]
Compression tolerance for SZ3 or ZFP.
Definition: mptrac.h:2625
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2379
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3141
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3159
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3171
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2310
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2656
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2406
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3162
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2433
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2747
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3216
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2493
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2719
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3132
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2644
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2331
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2475
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3243
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3075
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3177
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3102
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2337
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3147
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2460
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2716
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2689
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2307
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3183
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2313
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3186
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3078
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2725
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3087
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2686
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2668
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2671
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3129
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2647
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3189
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2370
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2741
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3195
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2292
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2756
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2502
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2430
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3096
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3240
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3268
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3060
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2707
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2987
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3072
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2328
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2319
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3249
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2822
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3219
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2421
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3126
int met_comp_prec[METVAR]
Compression precision for SZ3 or ZFP.
Definition: mptrac.h:2622
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2349
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2469
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2674
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2734
int met_dx
Stride for longitudes.
Definition: mptrac.h:2677
int qnt_destination
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2571
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2596
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2481
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2990
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2783
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2352
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3258
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2367
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2424
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2373
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3204
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2472
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2361
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3225
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3069
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3144
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2662
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2316
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2638
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3165
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:3039
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2340
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2400
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3192
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2710
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2358
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3048
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2984
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3120
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:2600
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3093
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2496
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3234
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3168
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2695
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2641
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2412
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2418
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3150
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2325
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3123
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3213
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3051
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2722
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3045
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3210
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2628
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:3029
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2692
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3198
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2394
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2442
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2457
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2713
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3207
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2415
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:3032
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3201
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2665
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2616
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2981
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3066
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2659
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2631
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3138
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3246
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2343
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2613
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2909
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3255
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2650
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2505
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2334
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3063
int met_cms_heur
cmultiscale coarsening heuristics (0=default, 1=mean diff, 2=median diff, 3=max diff).
Definition: mptrac.h:2635
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2466
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2322
int met_dy
Stride for latitudes.
Definition: mptrac.h:2680
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3271
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2286
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2744
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2382
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2277
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3222
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3252
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3228
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3174
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3274
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2346
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2391
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2403
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3135
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2508
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.
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 6357 of file mptrac.c.

6362 {
6363
6364 /* Write info... */
6365 LOG(1, "Read meteo data: %s", filename);
6366
6367 /* Set rank... */
6368 int rank = 0;
6369#ifdef MPI
6370 if (ctl->met_mpi_share)
6371 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
6372#endif
6373
6374 /* Check rank... */
6375 if (!ctl->met_mpi_share || rank == 0) {
6376
6377 /* Read netCDF data... */
6378 if (ctl->met_type == 0) {
6379 if (read_met_nc(filename, ctl, met, dd) != 1)
6380 return 0;
6381 }
6382
6383 /* Read binary data... */
6384 else if ((ctl->met_type >= 1 && ctl->met_type <= 5) || ctl->met_type == 7) {
6385 if (read_met_bin(filename, ctl, met) != 1)
6386 return 0;
6387 }
6388
6389#ifdef ECCODES
6390 /* Read grib data... */
6391 else if (ctl->met_type == 6) {
6392 if (read_met_grib(filename, ctl, met) != 1)
6393 return 0;
6394 }
6395#endif
6396
6397 /* Not implemented... */
6398 else
6399 ERRMSG("MET_TYPE not implemented!");
6400
6401 /* Preprocessing for netCDF and grib files... */
6402 if (ctl->met_type == 0 || ctl->met_type == 6) {
6403
6404 /* Extrapolate data for lower boundary... */
6406
6407 /* Fix polar winds... */
6409
6410 /* Create periodic boundary conditions... */
6411#ifndef DD
6412 read_met_periodic(met);
6413#endif
6414
6415 /* Downsampling... */
6416 read_met_sample(ctl, met);
6417
6418 /* Calculate geopotential heights... */
6419 read_met_geopot(ctl, met);
6420
6421 /* Calculate potential vorticity... */
6422 read_met_pv(met);
6423
6424 /* Calculate boundary layer data... */
6425 read_met_pbl(ctl, met);
6426
6427 /* Calculate tropopause data... */
6428 read_met_tropo(ctl, clim, met);
6429
6430 /* Calculate cloud properties... */
6431 read_met_cloud(met);
6432
6433 /* Calculate convective available potential energy... */
6434 read_met_cape(ctl, clim, met);
6435
6436 /* Calculate total column ozone... */
6437 read_met_ozone(met);
6438
6439 /* Detrending... */
6440 read_met_detrend(ctl, met);
6441
6442 /* Check meteo data and smooth zeta profiles ... */
6443 read_met_monotonize(ctl, met);
6444 }
6445 }
6446
6447 /* Broadcast data via MPI... */
6448#ifdef MPI
6449 if (ctl->met_mpi_share) {
6450
6451 /* Set timer... */
6452 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
6453 LOG(2, "Broadcast data on rank %d...", rank);
6454
6455 /* Broadcast... */
6456 broadcast_large_data(met, sizeof(met_t));
6457 }
6458#endif
6459
6460 /* Return success... */
6461 return 1;
6462}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:8070
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:8030
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:10453
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:7869
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:10061
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:7926
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:9696
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:10198
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:9781
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:10424
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:10318
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:7471
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:10259
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:7754
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 6466 of file mptrac.c.

6474 {
6475
6476 /* Initialize modules... */
6477 if (t == ctl->t_start) {
6478
6479 /* Initialize isosurface data... */
6480 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6481 module_isosurf_init(ctl, cache, *met0, *met1, atm);
6482
6483 /* Initialize advection... */
6484 module_advect_init(ctl, cache, *met0, *met1, atm);
6485
6486 /* Initialize chemistry... */
6487 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
6488 }
6489
6490 /* Set time steps of air parcels... */
6491 module_timesteps(ctl, cache, *met0, atm, t);
6492
6493 /* Sort particles... */
6494 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
6495 module_sort(ctl, *met0, atm);
6496
6497
6498 /* Check positions (initial)... */
6499 module_position(cache, *met0, *met1, atm);
6500
6501 /* Advection... */
6502 if (ctl->advect > 0)
6503 module_advect(ctl, cache, *met0, *met1, atm);
6504
6505 /* Turbulent diffusion... */
6506 if (ctl->diffusion == 1
6507 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
6508 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
6509 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
6510 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
6511
6512 /* Mesoscale diffusion... */
6513 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
6514 module_diff_meso(ctl, cache, *met0, *met1, atm);
6515
6516 /* Diffusion... */
6517 if (ctl->diffusion == 2)
6518 module_diff_pbl(ctl, cache, *met0, *met1, atm);
6519
6520 /* Convection... */
6521 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
6522 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
6523 module_convection(ctl, cache, *met0, *met1, atm);
6524
6525 /* Sedimentation... */
6526 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
6527 module_sedi(ctl, cache, *met0, *met1, atm);
6528
6529 /* Isosurface... */
6530 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6531 module_isosurf(ctl, cache, *met0, *met1, atm);
6532
6533 /* Check positions (final)... */
6534 module_position(cache, *met0, *met1, atm);
6535
6536 /* Interpolate meteo data... */
6537 if (ctl->met_dt_out > 0
6538 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
6539 module_meteo(ctl, cache, clim, *met0, *met1, atm);
6540
6541 /* Check boundary conditions (initial)... */
6542 if ((ctl->bound_lat0 < ctl->bound_lat1)
6543 && (ctl->bound_p0 > ctl->bound_p1))
6544 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6545
6546 /* Initialize quantity of total loss rate... */
6547 if (ctl->qnt_loss_rate >= 0) {
6548 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
6549 atm->q[ctl->qnt_loss_rate][ip] = 0;
6550 }
6551 }
6552
6553 /* Decay of particle mass... */
6554 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
6555 module_decay(ctl, cache, clim, atm);
6556
6557 /* Interparcel mixing... */
6558 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
6559 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
6560 module_mixing(ctl, clim, atm, t);
6561
6562 /* Calculate the tracer vmr in the chemistry grid... */
6563 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
6564 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
6565 module_chem_grid(ctl, *met0, *met1, atm, t);
6566
6567 /* OH chemistry... */
6568 if (ctl->oh_chem_reaction != 0)
6569 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
6570
6571 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
6572 if (ctl->h2o2_chem_reaction != 0)
6573 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
6574
6575 /* First-order tracer chemistry... */
6576 if (ctl->tracer_chem)
6577 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
6578
6579 /* Domain decomposition... */
6580 if (dd->init) {
6581#ifdef DD
6582 module_dd(ctl, atm, cache, dd, met0);
6583#else
6584 ERRMSG("DD initialized, but model is compiled without DD.")
6585#endif
6586 }
6587
6588 /* KPP chemistry... */
6589 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
6590#ifdef KPP
6591 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
6592#else
6593 ERRMSG("Code was compiled without KPP!");
6594#endif
6595 }
6596
6597 /* Wet deposition... */
6598 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
6599 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
6600 module_wet_depo(ctl, cache, *met0, *met1, atm);
6601
6602 /* Dry deposition... */
6603 if (ctl->dry_depo_vdep > 0)
6604 module_dry_depo(ctl, cache, *met0, *met1, atm);
6605
6606 /* Check boundary conditions (final)... */
6607 if ((ctl->bound_lat0 < ctl->bound_lat1)
6608 && (ctl->bound_p0 > ctl->bound_p1))
6609 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6610}
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:2925
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:4825
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:4142
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:3528
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:3373
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:4249
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:3966
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:4973
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:3211
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:4693
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:3415
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:3115
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:3088
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:4506
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:3567
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:4722
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:3769
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:4903
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:3884
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:3644
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:4036
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:4422
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:3821
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:3779
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 6614 of file mptrac.c.

6620 {
6621
6622 /* Update GPU... */
6623 if (ctl != NULL) {
6624#ifdef _OPENACC
6625 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6626#pragma acc update device(ctl[:1])
6627#endif
6628 }
6629
6630 if (cache != NULL) {
6631#ifdef _OPENACC
6632 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6633#pragma acc update device(cache[:1])
6634#endif
6635 }
6636
6637 if (clim != NULL) {
6638#ifdef _OPENACC
6639 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6640#pragma acc update device(clim[:1])
6641#endif
6642 }
6643
6644 if (met0 != NULL) {
6645#ifdef _OPENACC
6646 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6647 met_t *met0up = *met0;
6648#pragma acc update device(met0up[:1])
6649#endif
6650 }
6651
6652 if (met1 != NULL) {
6653#ifdef _OPENACC
6654 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6655 met_t *met1up = *met1;
6656#pragma acc update device(met1up[:1])
6657#endif
6658 }
6659
6660 if (atm != NULL) {
6661#ifdef _OPENACC
6662 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6663#pragma acc update device(atm[:1])
6664#endif
6665 }
6666}

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

6676 {
6677
6678 /* Update GPU... */
6679 if (ctl != NULL) {
6680#ifdef _OPENACC
6681 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6682#pragma acc update host(ctl[:1])
6683#endif
6684 }
6685
6686 if (cache != NULL) {
6687#ifdef _OPENACC
6688 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6689#pragma acc update host(cache[:1])
6690#endif
6691 }
6692
6693 if (clim != NULL) {
6694#ifdef _OPENACC
6695 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6696#pragma acc update host(clim[:1])
6697#endif
6698 }
6699
6700 if (met0 != NULL) {
6701#ifdef _OPENACC
6702 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6703 met_t *met0up = *met0;
6704#pragma acc update host(met0up[:1])
6705#endif
6706 }
6707
6708 if (met1 != NULL) {
6709#ifdef _OPENACC
6710 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6711 met_t *met1up = *met1;
6712#pragma acc update host(met1up[:1])
6713#endif
6714 }
6715
6716 if (atm != NULL) {
6717#ifdef _OPENACC
6718 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6719#pragma acc update host(atm[:1])
6720#endif
6721 }
6722}

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

6730 {
6731
6732 /* Set timer... */
6733 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
6734
6735 /* Write info... */
6736 LOG(1, "Write atmospheric data: %s", filename);
6737
6738 /* Write ASCII data... */
6739 if (ctl->atm_type_out == 0)
6740 write_atm_asc(filename, ctl, atm, t);
6741
6742 /* Write binary data... */
6743 else if (ctl->atm_type_out == 1)
6744 write_atm_bin(filename, ctl, atm);
6745
6746 /* Write netCDF data... */
6747 else if (ctl->atm_type_out == 2)
6748 write_atm_nc(filename, ctl, atm);
6749
6750 /* Write CLaMS trajectory data... */
6751 else if (ctl->atm_type_out == 3)
6752 write_atm_clams_traj(filename, ctl, atm, t);
6753
6754 /* Write CLaMS pos data... */
6755 else if (ctl->atm_type_out == 4)
6756 write_atm_clams(filename, ctl, atm);
6757
6758 /* Error... */
6759 else
6760 ERRMSG("Atmospheric data type not supported!");
6761
6762 /* Write info... */
6763 double mini, maxi;
6764 LOG(2, "Number of particles: %d", atm->np);
6765 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6766 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6767 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6768 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6769 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6770 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6771 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
6772 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6773 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
6774 for (int iq = 0; iq < ctl->nq; iq++) {
6775 char msg[5 * LEN];
6776 sprintf(msg, "Quantity %s range: %s ... %s %s",
6777 ctl->qnt_name[iq], ctl->qnt_format[iq],
6778 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6779 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6780 LOG(2, msg, mini, maxi);
6781 }
6782}
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:11455
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:11270
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:11402
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:11352
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:11613
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 6786 of file mptrac.c.

6789 {
6790
6791 /* Set timer... */
6792 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
6793
6794 /* Write info... */
6795 LOG(1, "Write meteo data: %s", filename);
6796
6797 /* Check compression flags... */
6798#ifndef ZFP
6799 if (ctl->met_type == 3)
6800 ERRMSG("MPTRAC was compiled without ZFP compression!");
6801#endif
6802#ifndef ZSTD
6803 if (ctl->met_type == 4)
6804 ERRMSG("MPTRAC was compiled without ZSTD compression!");
6805#endif
6806#ifndef CMS
6807 if (ctl->met_type == 5)
6808 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6809#endif
6810#ifndef SZ3
6811 if (ctl->met_type == 7)
6812 ERRMSG("MPTRAC was compiled without SZ3 compression!");
6813#endif
6814
6815 /* Write netCDF data... */
6816 if (ctl->met_type == 0)
6817 write_met_nc(filename, ctl, met);
6818
6819 /* Write binary data... */
6820 else if (ctl->met_type >= 1 && ctl->met_type <= 7)
6821 write_met_bin(filename, ctl, met);
6822
6823 /* Not implemented... */
6824 else
6825 ERRMSG("MET_TYPE not implemented!");
6826}
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:12690
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:12459
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 6830 of file mptrac.c.

6836 {
6837
6838 char ext[10], filename[2 * LEN];
6839
6840 double r;
6841
6842 int year, mon, day, hour, min, sec;
6843
6844 /* Get time... */
6845 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
6846
6847 /* Update host... */
6848 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
6849 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
6850 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
6851 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
6852 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
6853 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
6854 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
6855
6856 /* Write atmospheric data... */
6857 if (ctl->atm_basename[0] != '-' &&
6858 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
6859 if (ctl->atm_type_out == 0)
6860 sprintf(ext, "tab");
6861 else if (ctl->atm_type_out == 1)
6862 sprintf(ext, "bin");
6863 else if (ctl->atm_type_out == 2)
6864 sprintf(ext, "nc");
6865 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6866 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
6867 mptrac_write_atm(filename, ctl, atm, t);
6868 }
6869
6870 /* Write gridded data... */
6871 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
6872 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6873 dirname, ctl->grid_basename, year, mon, day, hour, min,
6874 ctl->grid_type == 0 ? "tab" : "nc");
6875 write_grid(filename, ctl, met0, met1, atm, t);
6876 }
6877
6878 /* Write CSI data... */
6879 if (ctl->csi_basename[0] != '-') {
6880 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
6881 write_csi(filename, ctl, atm, t);
6882 }
6883
6884 /* Write ensemble data... */
6885 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
6886 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
6887 dirname, ctl->ens_basename, year, mon, day, hour, min);
6888 write_ens(filename, ctl, atm, t);
6889 }
6890
6891 /* Write profile data... */
6892 if (ctl->prof_basename[0] != '-') {
6893 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
6894 write_prof(filename, ctl, met0, met1, atm, t);
6895 }
6896
6897 /* Write sample data... */
6898 if (ctl->sample_basename[0] != '-') {
6899 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
6900 write_sample(filename, ctl, met0, met1, atm, t);
6901 }
6902
6903 /* Write station data... */
6904 if (ctl->stat_basename[0] != '-') {
6905 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
6906 write_station(filename, ctl, atm, t);
6907 }
6908
6909 /* Write VTK data... */
6910 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
6911 static int nvtk;
6912 if (t == ctl->t_start)
6913 nvtk = 0;
6914 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
6915 write_vtk(filename, ctl, atm, t);
6916 }
6917}
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:6726
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:11937
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:12913
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:6670
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:13302
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:13388
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:13140
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:12034
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:11662
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 6921 of file mptrac.c.

6924 {
6925
6926 /* Check water vapor volume mixing ratio... */
6927 const double h2o_help = MAX(h2o, 0.1e-6);
6928
6929 /* Calculate T_NAT... */
6930 const double p_hno3 = hno3 * p / 1.333224;
6931 const double p_h2o = h2o_help * p / 1.333224;
6932 const double a = 0.009179 - 0.00088 * log10(p_h2o);
6933 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
6934 const double c = -11397.0 / a;
6935 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
6936 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
6937 if (x2 > 0)
6938 tnat = x2;
6939
6940 return tnat;
6941}

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

6950 {
6951
6952 /* Get pressure range... */
6953 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
6954 const double p0 = pbl;
6955
6956 /* Get weighting factor... */
6957 if (atm->p[ip] > p0)
6958 return 1;
6959 else if (atm->p[ip] < p1)
6960 return 0;
6961 else
6962 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
6963}

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

6970 {
6971
6972 /* Open file... */
6973 FILE *in;
6974 if (!(in = fopen(filename, "r"))) {
6975 WARN("Cannot open file!");
6976 return 0;
6977 }
6978
6979 /* Read line... */
6980 char line[LEN];
6981 while (fgets(line, LEN, in)) {
6982
6983 /* Read data... */
6984 char *tok;
6985 TOK(line, tok, "%lg", atm->time[atm->np]);
6986 TOK(NULL, tok, "%lg", atm->p[atm->np]);
6987 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
6988 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
6989 for (int iq = 0; iq < ctl->nq; iq++)
6990 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
6991
6992 /* Convert altitude to pressure... */
6993 atm->p[atm->np] = P(atm->p[atm->np]);
6994
6995 /* Increment data point counter... */
6996 if ((++atm->np) > NP)
6997 ERRMSG("Too many data points!");
6998 }
6999
7000 /* Close file... */
7001 fclose(in);
7002
7003 /* Return success... */
7004 return 1;
7005}
#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 7009 of file mptrac.c.

7012 {
7013
7014 /* Open file... */
7015 FILE *in;
7016 if (!(in = fopen(filename, "r")))
7017 return 0;
7018
7019 /* Check version of binary data... */
7020 int version;
7021 FREAD(&version, int,
7022 1,
7023 in);
7024 if (version != 100)
7025 ERRMSG("Wrong version of binary data!");
7026
7027 /* Read data... */
7028 FREAD(&atm->np, int,
7029 1,
7030 in);
7031 FREAD(atm->time, double,
7032 (size_t) atm->np,
7033 in);
7034 FREAD(atm->p, double,
7035 (size_t) atm->np,
7036 in);
7037 FREAD(atm->lon, double,
7038 (size_t) atm->np,
7039 in);
7040 FREAD(atm->lat, double,
7041 (size_t) atm->np,
7042 in);
7043 for (int iq = 0; iq < ctl->nq; iq++)
7044 FREAD(atm->q[iq], double,
7045 (size_t) atm->np,
7046 in);
7047
7048 /* Read final flag... */
7049 int final;
7050 FREAD(&final, int,
7051 1,
7052 in);
7053 if (final != 999)
7054 ERRMSG("Error while reading binary data!");
7055
7056 /* Close file... */
7057 fclose(in);
7058
7059 /* Return success... */
7060 return 1;
7061}

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

7068 {
7069
7070 int ncid, varid;
7071
7072 /* Open file... */
7073 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7074 return 0;
7075
7076 /* Get dimensions... */
7077 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
7078
7079 /* Get time... */
7080 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
7081 NC(nc_get_var_double(ncid, varid, atm->time));
7082 } else {
7083 WARN("TIME_INIT not found use time instead!");
7084 double time_init;
7085 NC_GET_DOUBLE("time", &time_init, 1);
7086 for (int ip = 0; ip < atm->np; ip++) {
7087 atm->time[ip] = time_init;
7088 }
7089 }
7090
7091 /* Read zeta coordinate, pressure is optional... */
7092 if (ctl->advect_vert_coord == 1) {
7093 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
7094 NC_GET_DOUBLE("PRESS", atm->p, 0);
7095 }
7096
7097 /* Read pressure, zeta coordinate is optional... */
7098 else {
7099 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
7100 NC(nc_get_var_double(ncid, varid, atm->p));
7101 } else {
7102 WARN("PRESS_INIT not found use PRESS instead!");
7103 nc_inq_varid(ncid, "PRESS", &varid);
7104 NC(nc_get_var_double(ncid, varid, atm->p));
7105 }
7106 }
7107
7108 /* Read further quantities if requested... */
7109 for (int iq = 0; iq < ctl->nq; iq++)
7110 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7111
7112 /* Read longitude and latitude... */
7113 NC_GET_DOUBLE("LON", atm->lon, 1);
7114 NC_GET_DOUBLE("LAT", atm->lat, 1);
7115
7116 /* Close file... */
7117 NC(nc_close(ncid));
7118
7119 /* Return success... */
7120 return 1;
7121}
#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 7125 of file mptrac.c.

7128 {
7129
7130 int ncid, varid;
7131
7132 /* Open file... */
7133 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7134 return 0;
7135
7136 /* Get dimensions... */
7137 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
7138
7139 /* Read geolocations... */
7140 NC_GET_DOUBLE("time", atm->time, 1);
7141 NC_GET_DOUBLE("press", atm->p, 1);
7142 NC_GET_DOUBLE("lon", atm->lon, 1);
7143 NC_GET_DOUBLE("lat", atm->lat, 1);
7144
7145 /* Read variables... */
7146 for (int iq = 0; iq < ctl->nq; iq++)
7147 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7148
7149 /* Close file... */
7150 NC(nc_close(ncid));
7151
7152 /* Return success... */
7153 return 1;
7154}

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

7160 {
7161
7162 int ncid, varid;
7163
7164 /* Write info... */
7165 LOG(1, "Read photolysis rates: %s", filename);
7166
7167 /* Open netCDF file... */
7168 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7169 WARN("Photolysis rate data are missing!");
7170 return;
7171 }
7172
7173 /* Read pressure data... */
7174 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
7175 NC_GET_DOUBLE("press", photo->p, 1);
7176 if (photo->p[0] < photo->p[1])
7177 ERRMSG("Pressure data are not descending!");
7178
7179 /* Read total column ozone data... */
7180 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
7181 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
7182 if (photo->o3c[0] > photo->o3c[1])
7183 ERRMSG("Total column ozone data are not ascending!");
7184
7185 /* Read solar zenith angle data... */
7186 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
7187 NC_GET_DOUBLE("sza", photo->sza, 1);
7188 if (photo->sza[0] > photo->sza[1])
7189 ERRMSG("Solar zenith angle data are not ascending!");
7190
7191 /* Read data... */
7192 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
7193 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
7194 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
7195 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
7196 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
7197 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
7198 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
7199 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
7200 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
7201
7202 /* Close netCDF file... */
7203 NC(nc_close(ncid));
7204
7205 /* Write info... */
7206 LOG(2, "Number of pressure levels: %d", photo->np);
7207 LOG(2, "Altitude levels: %g, %g ... %g km",
7208 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
7209 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7210 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
7211 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
7212 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
7213 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
7214 RAD2DEG(photo->sza[photo->nsza - 1]));
7215 LOG(2, "Number of total column ozone values: %d", photo->no3c);
7216 LOG(2, "Total column ozone: %g, %g ... %g DU",
7217 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
7218 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
7219 photo->n2o[0][0][0], photo->n2o[1][0][0],
7220 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7221 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
7222 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
7223 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7224 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
7225 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
7226 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7227 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
7228 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
7229 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7230 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
7231 photo->o2[0][0][0], photo->o2[1][0][0],
7232 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7233 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
7234 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
7235 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7236 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
7237 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
7238 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7239 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
7240 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
7241 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7242 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
7243 photo->h2o[0][0][0], photo->h2o[1][0][0],
7244 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7245}
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:7249
#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:3415
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3412
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3421
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3424
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3418
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 7249 of file mptrac.c.

7253 {
7254
7255 /* Allocate... */
7256 double *help;
7257 ALLOC(help, double,
7258 photo->np * photo->nsza * photo->no3c);
7259
7260 /* Read varible... */
7261 int varid;
7262 NC_GET_DOUBLE(varname, help, 1);
7263
7264 /* Copy data... */
7265 for (int ip = 0; ip < photo->np; ip++)
7266 for (int is = 0; is < photo->nsza; is++)
7267 for (int io = 0; io < photo->no3c; io++)
7268 var[ip][is][io] =
7269 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
7270
7271 /* Free... */
7272 free(help);
7273}

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

7279 {
7280
7281 /* Write info... */
7282 LOG(1, "Read climatological time series: %s", filename);
7283
7284 /* Open file... */
7285 FILE *in;
7286 if (!(in = fopen(filename, "r"))) {
7287 WARN("Cannot open file!");
7288 return 0;
7289 }
7290
7291 /* Read data... */
7292 char line[LEN];
7293 int nh = 0;
7294 while (fgets(line, LEN, in))
7295 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
7296
7297 /* Convert years to seconds... */
7298 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
7299
7300 /* Check data... */
7301 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
7302 ERRMSG("Time series must be ascending!");
7303
7304 /* Count time steps... */
7305 if ((++nh) >= CTS)
7306 ERRMSG("Too many data points!");
7307 }
7308
7309 /* Close file... */
7310 fclose(in);
7311
7312 /* Check number of data points... */
7313 ts->ntime = nh;
7314 if (nh < 2)
7315 ERRMSG("Not enough data points!");
7316
7317 /* Write info... */
7318 LOG(2, "Number of time steps: %d", ts->ntime);
7319 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
7320 ts->time[nh - 1]);
7321 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
7322 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
7323 (size_t) nh));
7324
7325 /* Exit success... */
7326 return 1;
7327}
#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 7331 of file mptrac.c.

7334 {
7335
7336 int ncid, varid, it, iy, iz, iz2, nt;
7337
7338 double *help, varmin = 1e99, varmax = -1e99;
7339
7340 /* Write info... */
7341 LOG(1, "Read %s data: %s", varname, filename);
7342
7343 /* Open netCDF file... */
7344 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7345 WARN("%s climatology data are missing!", varname);
7346 return;
7347 }
7348
7349 /* Read pressure data... */
7350 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
7351 NC_GET_DOUBLE("press", zm->p, 1);
7352 if (zm->p[0] < zm->p[1])
7353 ERRMSG("Pressure data are not descending!");
7354
7355 /* Read latitudes... */
7356 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
7357 NC_GET_DOUBLE("lat", zm->lat, 1);
7358 if (zm->lat[0] > zm->lat[1])
7359 ERRMSG("Latitude data are not ascending!");
7360
7361 /* Set time data (for monthly means)... */
7362 zm->ntime = 12;
7363 zm->time[0] = 1209600.00;
7364 zm->time[1] = 3888000.00;
7365 zm->time[2] = 6393600.00;
7366 zm->time[3] = 9072000.00;
7367 zm->time[4] = 11664000.00;
7368 zm->time[5] = 14342400.00;
7369 zm->time[6] = 16934400.00;
7370 zm->time[7] = 19612800.00;
7371 zm->time[8] = 22291200.00;
7372 zm->time[9] = 24883200.00;
7373 zm->time[10] = 27561600.00;
7374 zm->time[11] = 30153600.00;
7375
7376 /* Check number of timesteps... */
7377 NC_INQ_DIM("time", &nt, 12, 12, 1);
7378
7379 /* Read data... */
7380 ALLOC(help, double,
7381 zm->nlat * zm->np * zm->ntime);
7382 NC_GET_DOUBLE(varname, help, 1);
7383 for (it = 0; it < zm->ntime; it++)
7384 for (iz = 0; iz < zm->np; iz++)
7385 for (iy = 0; iy < zm->nlat; iy++)
7386 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
7387 free(help);
7388
7389 /* Fix data gaps... */
7390 for (it = 0; it < zm->ntime; it++)
7391 for (iy = 0; iy < zm->nlat; iy++)
7392 for (iz = 0; iz < zm->np; iz++) {
7393 if (zm->vmr[it][iz][iy] < 0) {
7394 for (iz2 = 0; iz2 < zm->np; iz2++)
7395 if (zm->vmr[it][iz2][iy] >= 0) {
7396 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7397 break;
7398 }
7399 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
7400 if (zm->vmr[it][iz2][iy] >= 0) {
7401 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7402 break;
7403 }
7404 }
7405 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
7406 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
7407 }
7408
7409 /* Close netCDF file... */
7410 NC(nc_close(ncid));
7411
7412 /* Write info... */
7413 LOG(2, "Number of time steps: %d", zm->ntime);
7414 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
7415 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
7416 LOG(2, "Number of pressure levels: %d", zm->np);
7417 LOG(2, "Altitude levels: %g, %g ... %g km",
7418 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
7419 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
7420 zm->p[1], zm->p[zm->np - 1]);
7421 LOG(2, "Number of latitudes: %d", zm->nlat);
7422 LOG(2, "Latitudes: %g, %g ... %g deg",
7423 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
7424 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
7425 varmax);
7426}
#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 7430 of file mptrac.c.

7434 {
7435
7436 /* Write info... */
7437 LOG(1, "Read kernel function: %s", filename);
7438
7439 /* Open file... */
7440 FILE *in;
7441 if (!(in = fopen(filename, "r")))
7442 ERRMSG("Cannot open file!");
7443
7444 /* Read data... */
7445 char line[LEN];
7446 int n = 0;
7447 while (fgets(line, LEN, in))
7448 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
7449 if (n > 0 && kz[n] < kz[n - 1])
7450 ERRMSG("Height levels must be ascending!");
7451 if ((++n) >= EP)
7452 ERRMSG("Too many height levels!");
7453 }
7454
7455 /* Close file... */
7456 fclose(in);
7457
7458 /* Check number of data points... */
7459 *nk = n;
7460 if (n < 2)
7461 ERRMSG("Not enough height levels!");
7462
7463 /* Normalize kernel function... */
7464 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
7465 for (int iz = 0; iz < n; iz++)
7466 kw[iz] /= kmax;
7467}

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

7474 {
7475
7476 FILE *in;
7477
7478 double r;
7479
7480 int year, mon, day, hour, min, sec;
7481
7482 /* Set timer... */
7483 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
7484
7485 /* Open file... */
7486 if (!(in = fopen(filename, "r"))) {
7487 WARN("Cannot open file!");
7488 return 0;
7489 }
7490
7491 /* Check type of binary data... */
7492 int met_type;
7493 FREAD(&met_type, int,
7494 1,
7495 in);
7496 if (met_type != ctl->met_type)
7497 ERRMSG("Wrong MET_TYPE of binary data!");
7498
7499 /* Check version of binary data... */
7500 int version;
7501 FREAD(&version, int,
7502 1,
7503 in);
7504 if (version != 103)
7505 ERRMSG("Wrong version of binary data!");
7506
7507 /* Read time... */
7508 FREAD(&met->time, double,
7509 1,
7510 in);
7511 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7512 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7513 met->time, year, mon, day, hour, min);
7514 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7515 || day < 1 || day > 31 || hour < 0 || hour > 23)
7516 ERRMSG("Error while reading time!");
7517
7518 /* Read dimensions... */
7519 FREAD(&met->nx, int,
7520 1,
7521 in);
7522 LOG(2, "Number of longitudes: %d", met->nx);
7523 if (met->nx < 2 || met->nx > EX)
7524 ERRMSG("Number of longitudes out of range!");
7525
7526 FREAD(&met->ny, int,
7527 1,
7528 in);
7529 LOG(2, "Number of latitudes: %d", met->ny);
7530 if (met->ny < 2 || met->ny > EY)
7531 ERRMSG("Number of latitudes out of range!");
7532
7533 FREAD(&met->np, int,
7534 1,
7535 in);
7536 LOG(2, "Number of levels: %d", met->np);
7537 if (met->np < 2 || met->np > EP)
7538 ERRMSG("Number of levels out of range!");
7539
7540 /* Read grid... */
7541 FREAD(met->lon, double,
7542 (size_t) met->nx,
7543 in);
7544 LOG(2, "Longitudes: %g, %g ... %g deg",
7545 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7546
7547 FREAD(met->lat, double,
7548 (size_t) met->ny,
7549 in);
7550 LOG(2, "Latitudes: %g, %g ... %g deg",
7551 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7552
7553 FREAD(met->p, double,
7554 (size_t) met->np,
7555 in);
7556 LOG(2, "Altitude levels: %g, %g ... %g km",
7557 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7558 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7559 met->p[0], met->p[1], met->p[met->np - 1]);
7560
7561 /* Read surface data... */
7562 read_met_bin_2d(in, met, met->ps, "PS");
7563 read_met_bin_2d(in, met, met->ts, "TS");
7564 read_met_bin_2d(in, met, met->zs, "ZS");
7565 read_met_bin_2d(in, met, met->us, "US");
7566 read_met_bin_2d(in, met, met->vs, "VS");
7567 read_met_bin_2d(in, met, met->ess, "ESS");
7568 read_met_bin_2d(in, met, met->nss, "NSS");
7569 read_met_bin_2d(in, met, met->shf, "SHF");
7570 read_met_bin_2d(in, met, met->lsm, "LSM");
7571 read_met_bin_2d(in, met, met->sst, "SST");
7572 read_met_bin_2d(in, met, met->pbl, "PBL");
7573 read_met_bin_2d(in, met, met->pt, "PT");
7574 read_met_bin_2d(in, met, met->tt, "TT");
7575 read_met_bin_2d(in, met, met->zt, "ZT");
7576 read_met_bin_2d(in, met, met->h2ot, "H2OT");
7577 read_met_bin_2d(in, met, met->pct, "PCT");
7578 read_met_bin_2d(in, met, met->pcb, "PCB");
7579 read_met_bin_2d(in, met, met->cl, "CL");
7580 read_met_bin_2d(in, met, met->plcl, "PLCL");
7581 read_met_bin_2d(in, met, met->plfc, "PLFC");
7582 read_met_bin_2d(in, met, met->pel, "PEL");
7583 read_met_bin_2d(in, met, met->cape, "CAPE");
7584 read_met_bin_2d(in, met, met->cin, "CIN");
7585 read_met_bin_2d(in, met, met->o3c, "O3C");
7586
7587 /* Read level data... */
7588 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
7589 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
7590 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
7591 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
7592 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
7593 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
7594 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
7595 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
7596 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
7597 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
7598 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
7599 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
7600 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
7601
7602 /* Read final flag... */
7603 int final;
7604 FREAD(&final, int,
7605 1,
7606 in);
7607 if (final != 999)
7608 ERRMSG("Error while reading binary data!");
7609
7610 /* Close file... */
7611 fclose(in);
7612
7613 /* Return success... */
7614 return 1;
7615}
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:7619
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:7648
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:293
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3624
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3612
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3684
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3654
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3648
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3630
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3606
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3681
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3594
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3693
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3588
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3600
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3633
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3645
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3651
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3639
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3621
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3615
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3597
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3609
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3687
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3627
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3672
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3636
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3603
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3642
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3690
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 7619 of file mptrac.c.

7623 {
7624
7625 float *help;
7626
7627 /* Allocate... */
7628 ALLOC(help, float,
7629 EX * EY);
7630
7631 /* Read uncompressed... */
7632 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
7633 FREAD(help, float,
7634 (size_t) (met->nx * met->ny),
7635 in);
7636
7637 /* Copy data... */
7638 for (int ix = 0; ix < met->nx; ix++)
7639 for (int iy = 0; iy < met->ny; iy++)
7640 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
7641
7642 /* Free... */
7643 free(help);
7644}
#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 7648 of file mptrac.c.

7655 {
7656
7657 float *help;
7658
7659 /* Allocate... */
7660 ALLOC(help, float,
7661 EX * EY * EP);
7662
7663 /* Read uncompressed data... */
7664 if (ctl->met_type == 1) {
7665 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
7666 FREAD(help, float,
7667 (size_t) (met->nx * met->ny * met->np),
7668 in);
7669 }
7670
7671 /* Read packed data... */
7672 else if (ctl->met_type == 2)
7673 compress_pck(varname, help, (size_t) (met->ny * met->nx),
7674 (size_t) met->np, 1, in);
7675
7676 /* Read ZFP data... */
7677 else if (ctl->met_type == 3) {
7678#ifdef ZFP
7679 int precision;
7680 FREAD(&precision, int,
7681 1,
7682 in);
7683
7684 double tolerance;
7685 FREAD(&tolerance, double,
7686 1,
7687 in);
7688
7689 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
7690 tolerance, 1, in);
7691#else
7692 ERRMSG("MPTRAC was compiled without ZFP compression!");
7693#endif
7694 }
7695
7696 /* Read zstd data... */
7697 else if (ctl->met_type == 4) {
7698#ifdef ZSTD
7699 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
7700 ctl->met_zstd_level, in);
7701#else
7702 ERRMSG("MPTRAC was compiled without ZSTD compression!");
7703#endif
7704 }
7705
7706 /* Read cmultiscale data... */
7707 else if (ctl->met_type == 5) {
7708#ifdef CMS
7709 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
7710 (size_t) met->np, 1, in);
7711#else
7712 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
7713#endif
7714 }
7715
7716 /* Read SZ3 data... */
7717 else if (ctl->met_type == 7) {
7718#ifdef SZ3
7719 int precision;
7720 FREAD(&precision, int,
7721 1,
7722 in);
7723
7724 double tolerance;
7725 FREAD(&tolerance, double,
7726 1,
7727 in);
7728
7729 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
7730 tolerance, 1, in);
7731#else
7732 ERRMSG("MPTRAC was compiled without sz3 compression!");
7733#endif
7734 }
7735
7736 /* Copy data... */
7737#pragma omp parallel for default(shared) collapse(2)
7738 for (int ix = 0; ix < met->nx; ix++)
7739 for (int iy = 0; iy < met->ny; iy++)
7740 for (int ip = 0; ip < met->np; ip++) {
7741 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7742 if (var[ix][iy][ip] < bound_min)
7743 var[ix][iy][ip] = bound_min;
7744 else if (var[ix][iy][ip] > bound_max)
7745 var[ix][iy][ip] = bound_max;
7746 }
7747
7748 /* Free... */
7749 free(help);
7750}
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:673
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 int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using a custom multiscale compression algorithm.
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.
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
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 7754 of file mptrac.c.

7757 {
7758
7759 /* Check parameters... */
7760 if (ctl->met_cape != 1)
7761 return;
7762
7763 /* Set timer... */
7764 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
7765 LOG(2, "Calculate CAPE...");
7766
7767 /* Vertical spacing (about 100 m)... */
7768 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
7769
7770 /* Loop over columns... */
7771#pragma omp parallel for default(shared) collapse(2)
7772 for (int ix = 0; ix < met->nx; ix++)
7773 for (int iy = 0; iy < met->ny; iy++) {
7774
7775 /* Get potential temperature and water vapor at lowest 50 hPa... */
7776 int n = 0;
7777 double h2o = 0, t, theta = 0;
7778 double pbot = MIN(met->ps[ix][iy], met->p[0]);
7779 double ptop = pbot - 50.;
7780 for (int ip = 0; ip < met->np; ip++) {
7781 if (met->p[ip] <= pbot) {
7782 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
7783 h2o += met->h2o[ix][iy][ip];
7784 n++;
7785 }
7786 if (met->p[ip] < ptop && n > 0)
7787 break;
7788 }
7789 theta /= n;
7790 h2o /= n;
7791
7792 /* Cannot compute anything if water vapor is missing... */
7793 met->plcl[ix][iy] = NAN;
7794 met->plfc[ix][iy] = NAN;
7795 met->pel[ix][iy] = NAN;
7796 met->cape[ix][iy] = NAN;
7797 met->cin[ix][iy] = NAN;
7798 if (h2o <= 0)
7799 continue;
7800
7801 /* Find lifted condensation level (LCL)... */
7802 ptop = P(20.);
7803 pbot = met->ps[ix][iy];
7804 do {
7805 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
7806 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
7807 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
7808 ptop = met->plcl[ix][iy];
7809 else
7810 pbot = met->plcl[ix][iy];
7811 } while (pbot - ptop > 0.1);
7812
7813 /* Calculate CIN up to LCL... */
7815 double dcape, dz, h2o_env, t_env;
7816 double p = met->ps[ix][iy];
7817 met->cape[ix][iy] = met->cin[ix][iy] = 0;
7818 do {
7819 dz = dz0 * TVIRT(t, h2o);
7820 p /= pfac;
7821 t = theta / pow(1000. / p, 0.286);
7822 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7823 &t_env, ci, cw, 1);
7824 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7825 &h2o_env, ci, cw, 0);
7826 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7827 TVIRT(t_env, h2o_env) * dz;
7828 if (dcape < 0)
7829 met->cin[ix][iy] += fabsf((float) dcape);
7830 } while (p > met->plcl[ix][iy]);
7831
7832 /* Calculate level of free convection (LFC), equilibrium level (EL),
7833 and convective available potential energy (CAPE)... */
7834 dcape = 0;
7835 p = met->plcl[ix][iy];
7836 t = theta / pow(1000. / p, 0.286);
7837 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
7838 do {
7839 dz = dz0 * TVIRT(t, h2o);
7840 p /= pfac;
7841 t -= lapse_rate(t, h2o) * dz;
7842 double psat = PSAT(t);
7843 h2o = psat / (p - (1. - EPS) * psat);
7844 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7845 &t_env, ci, cw, 1);
7846 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7847 &h2o_env, ci, cw, 0);
7848 double dcape_old = dcape;
7849 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7850 TVIRT(t_env, h2o_env) * dz;
7851 if (dcape > 0) {
7852 met->cape[ix][iy] += (float) dcape;
7853 if (!isfinite(met->plfc[ix][iy]))
7854 met->plfc[ix][iy] = (float) p;
7855 } else if (dcape_old > 0)
7856 met->pel[ix][iy] = (float) p;
7857 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
7858 met->cin[ix][iy] += fabsf((float) dcape);
7859 } while (p > ptop);
7860
7861 /* Check results... */
7862 if (!isfinite(met->plfc[ix][iy]))
7863 met->cin[ix][iy] = NAN;
7864 }
7865}
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:205
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 7869 of file mptrac.c.

7870 {
7871
7872 /* Set timer... */
7873 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
7874 LOG(2, "Calculate cloud data...");
7875
7876 /* Thresholds for cloud detection... */
7877 const double ccmin = 0.01, cwmin = 1e-6;
7878
7879 /* Loop over columns... */
7880#pragma omp parallel for default(shared) collapse(2)
7881 for (int ix = 0; ix < met->nx; ix++)
7882 for (int iy = 0; iy < met->ny; iy++) {
7883
7884 /* Init... */
7885 met->pct[ix][iy] = NAN;
7886 met->pcb[ix][iy] = NAN;
7887 met->cl[ix][iy] = 0;
7888
7889 /* Loop over pressure levels... */
7890 for (int ip = 0; ip < met->np - 1; ip++) {
7891
7892 /* Check pressure... */
7893 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
7894 continue;
7895
7896 /* Check ice water and liquid water content... */
7897 if (met->cc[ix][iy][ip] > ccmin
7898 && (met->lwc[ix][iy][ip] > cwmin
7899 || met->rwc[ix][iy][ip] > cwmin
7900 || met->iwc[ix][iy][ip] > cwmin
7901 || met->swc[ix][iy][ip] > cwmin)) {
7902
7903 /* Get cloud top pressure ... */
7904 met->pct[ix][iy]
7905 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
7906
7907 /* Get cloud bottom pressure ... */
7908 if (!isfinite(met->pcb[ix][iy]))
7909 met->pcb[ix][iy]
7910 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
7911 }
7912
7913 /* Get cloud water... */
7914 met->cl[ix][iy] += (float)
7915 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
7916 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
7917 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
7918 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
7919 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
7920 }
7921 }
7922}

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

7928 {
7929
7930 met_t *help;
7931
7932 /* Check parameters... */
7933 if (ctl->met_detrend <= 0)
7934 return;
7935
7936 /* Set timer... */
7937 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
7938 LOG(2, "Detrend meteo data...");
7939
7940 /* Allocate... */
7941 ALLOC(help, met_t, 1);
7942
7943 /* Calculate standard deviation... */
7944 const double sigma = ctl->met_detrend / 2.355;
7945 const double tssq = 2. * SQR(sigma);
7946
7947 /* Calculate box size in latitude... */
7948 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
7949 sy = MIN(MAX(1, sy), met->ny / 2);
7950
7951 /* Calculate background... */
7952#pragma omp parallel for default(shared) collapse(2)
7953 for (int ix = 0; ix < met->nx; ix++) {
7954 for (int iy = 0; iy < met->ny; iy++) {
7955
7956 /* Calculate Cartesian coordinates... */
7957 double x0[3];
7958 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
7959
7960 /* Calculate box size in longitude... */
7961 int sx =
7962 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
7963 fabs(met->lon[1] - met->lon[0]));
7964 sx = MIN(MAX(1, sx), met->nx / 2);
7965
7966 /* Init... */
7967 float wsum = 0;
7968 for (int ip = 0; ip < met->np; ip++) {
7969 help->t[ix][iy][ip] = 0;
7970 help->u[ix][iy][ip] = 0;
7971 help->v[ix][iy][ip] = 0;
7972 help->w[ix][iy][ip] = 0;
7973 }
7974
7975 /* Loop over neighboring grid points... */
7976 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
7977 int ix3 = ix2;
7978 if (ix3 < 0)
7979 ix3 += met->nx;
7980 else if (ix3 >= met->nx)
7981 ix3 -= met->nx;
7982 for (int iy2 = MAX(iy - sy, 0);
7983 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
7984
7985 /* Calculate Cartesian coordinates... */
7986 double x1[3];
7987 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
7988
7989 /* Calculate weighting factor... */
7990 const float w = (float) exp(-DIST2(x0, x1) / tssq);
7991
7992 /* Add data... */
7993 wsum += w;
7994 for (int ip = 0; ip < met->np; ip++) {
7995 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
7996 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
7997 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
7998 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
7999 }
8000 }
8001 }
8002
8003 /* Normalize... */
8004 for (int ip = 0; ip < met->np; ip++) {
8005 help->t[ix][iy][ip] /= wsum;
8006 help->u[ix][iy][ip] /= wsum;
8007 help->v[ix][iy][ip] /= wsum;
8008 help->w[ix][iy][ip] /= wsum;
8009 }
8010 }
8011 }
8012
8013 /* Subtract background... */
8014#pragma omp parallel for default(shared) collapse(3)
8015 for (int ix = 0; ix < met->nx; ix++)
8016 for (int iy = 0; iy < met->ny; iy++)
8017 for (int ip = 0; ip < met->np; ip++) {
8018 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
8019 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
8020 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
8021 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
8022 }
8023
8024 /* Free... */
8025 free(help);
8026}
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:1915
#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 8030 of file mptrac.c.

8031 {
8032
8033 /* Set timer... */
8034 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
8035 LOG(2, "Extrapolate meteo data...");
8036
8037 /* Loop over columns... */
8038#pragma omp parallel for default(shared) collapse(2)
8039 for (int ix = 0; ix < met->nx; ix++)
8040 for (int iy = 0; iy < met->ny; iy++) {
8041
8042 /* Find lowest valid data point... */
8043 int ip0;
8044 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
8045 if (!isfinite(met->t[ix][iy][ip0])
8046 || !isfinite(met->u[ix][iy][ip0])
8047 || !isfinite(met->v[ix][iy][ip0])
8048 || !isfinite(met->w[ix][iy][ip0]))
8049 break;
8050
8051 /* Extrapolate... */
8052 for (int ip = ip0; ip >= 0; ip--) {
8053 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
8054 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
8055 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
8056 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
8057 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
8058 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
8059 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
8060 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
8061 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
8062 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
8063 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
8064 }
8065 }
8066}

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

8072 {
8073
8074 float *help;
8075
8076 double logp[EP];
8077
8078 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
8079
8080 /* Set timer... */
8081 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
8082 LOG(2, "Calculate geopotential heights...");
8083
8084 /* Allocate... */
8085 ALLOC(help, float,
8086 EX * EY * EP);
8087
8088 /* Calculate log pressure... */
8089#pragma omp parallel for default(shared)
8090 for (int ip = 0; ip < met->np; ip++)
8091 logp[ip] = log(met->p[ip]);
8092
8093 /* Apply hydrostatic equation to calculate geopotential heights... */
8094#pragma omp parallel for default(shared) collapse(2)
8095 for (int ix = 0; ix < met->nx; ix++)
8096 for (int iy = 0; iy < met->ny; iy++) {
8097
8098 /* Get surface height and pressure... */
8099 const double zs = met->zs[ix][iy];
8100 const double lnps = log(met->ps[ix][iy]);
8101
8102 /* Get temperature and water vapor at the surface... */
8103 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
8104 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
8105 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
8106 const double h2os =
8107 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
8108 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
8109
8110 /* Upper part of profile... */
8111 met->z[ix][iy][ip0 + 1]
8112 = (float) (zs +
8113 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
8114 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
8115 for (int ip = ip0 + 2; ip < met->np; ip++)
8116 met->z[ix][iy][ip]
8117 = (float) (met->z[ix][iy][ip - 1] +
8118 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
8119 met->h2o[ix][iy][ip - 1], logp[ip],
8120 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8121
8122 /* Lower part of profile... */
8123 met->z[ix][iy][ip0]
8124 = (float) (zs +
8125 ZDIFF(lnps, ts, h2os, logp[ip0],
8126 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
8127 for (int ip = ip0 - 1; ip >= 0; ip--)
8128 met->z[ix][iy][ip]
8129 = (float) (met->z[ix][iy][ip + 1] +
8130 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
8131 met->h2o[ix][iy][ip + 1], logp[ip],
8132 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8133 }
8134
8135 /* Check control parameters... */
8136 if (dx == 0 || dy == 0)
8137 return;
8138
8139 /* Default smoothing parameters... */
8140 if (dx < 0 || dy < 0) {
8141 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
8142 dx = 3;
8143 dy = 2;
8144 } else {
8145 dx = 6;
8146 dy = 4;
8147 }
8148 }
8149
8150 /* Calculate weights for smoothing... */
8151 float ws[dx + 1][dy + 1];
8152#pragma omp parallel for default(shared) collapse(2)
8153 for (int ix = 0; ix <= dx; ix++)
8154 for (int iy = 0; iy < dy; iy++)
8155 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
8156 * (1.0f - (float) iy / (float) dy);
8157
8158 /* Copy data... */
8159#pragma omp parallel for default(shared) collapse(3)
8160 for (int ix = 0; ix < met->nx; ix++)
8161 for (int iy = 0; iy < met->ny; iy++)
8162 for (int ip = 0; ip < met->np; ip++)
8163 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
8164
8165 /* Horizontal smoothing... */
8166#pragma omp parallel for default(shared) collapse(3)
8167 for (int ip = 0; ip < met->np; ip++)
8168 for (int ix = 0; ix < met->nx; ix++)
8169 for (int iy = 0; iy < met->ny; iy++) {
8170 float res = 0, wsum = 0;
8171 int iy0 = MAX(iy - dy + 1, 0);
8172 int iy1 = MIN(iy + dy - 1, met->ny - 1);
8173 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
8174 int ix3 = ix2;
8175 if (ix3 < 0)
8176 ix3 += met->nx;
8177 else if (ix3 >= met->nx)
8178 ix3 -= met->nx;
8179 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
8180 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
8181 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
8182 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
8183 wsum += w;
8184 }
8185 }
8186 if (wsum > 0)
8187 met->z[ix][iy][ip] = res / wsum;
8188 else
8189 met->z[ix][iy][ip] = NAN;
8190 }
8191
8192 /* Free... */
8193 free(help);
8194}
#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.
ctlA pointer to a ctl_t structure containing control parameters.
metA pointer to a met_t structure where meteorological data will be stored.

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

8203 {
8204
8205 char levname[LEN], tstr[10];
8206
8207 double rtime = 0, r, r2;
8208
8209 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
8210 year, mon, day, hour, min, sec;
8211
8212 size_t dimlen;
8213
8214 /* Set timer... */
8215 SELECT_TIMER("READ_MET_NC_GRID", "INPUT", NVTX_READ);
8216 LOG(2, "Read meteo grid information...");
8217
8218 /* MPTRAC meteo files... */
8219 if (!ctl->met_clams) {
8220
8221 /* Get time from filename... */
8222 met->time = time_from_filename(filename, 16);
8223
8224 /* Check time information from data file... */
8225 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8226 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
8227 NC(nc_get_var_double(ncid, varid, &rtime));
8228 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
8229 WARN("Time information in meteo file does not match filename!");
8230 } else
8231 WARN("Time information in meteo file is missing!");
8232 }
8233
8234 /* CLaMS meteo files... */
8235 else {
8236
8237 /* Read time from file... */
8238 NC_GET_DOUBLE("time", &rtime, 0);
8239
8240 /* Get time from filename (considering the century)... */
8241 if (rtime < 0)
8242 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
8243 else
8244 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
8245 year = atoi(tstr);
8246 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
8247 mon = atoi(tstr);
8248 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
8249 day = atoi(tstr);
8250 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
8251 hour = atoi(tstr);
8252 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
8253 }
8254
8255 /* Check time... */
8256 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8257 || day < 1 || day > 31 || hour < 0 || hour > 23)
8258 ERRMSG("Cannot read time from filename!");
8259 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
8260 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8261 met->time, year2, mon2, day2, hour2, min2);
8262
8263 /* Get vertical dimension... */
8264 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
8265 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
8266 ERRMSG
8267 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
8268
8269 NC(nc_inq_varndims(ncid, varid, &ndims));
8270 NC(nc_inq_vardimid(ncid, varid, dimids));
8271
8272 if (ndims == 4) {
8273 NC(nc_inq_dim
8274 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
8275 } else if (ndims == 3) {
8276 NC(nc_inq_dim
8277 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
8278 } else
8279 ERRMSG("Cannot determine vertical dimension!")
8280 met->np = (int) dimlen;
8281
8282 LOG(2, "Number of levels: %d", met->np);
8283 if (met->np < 2 || met->np > EP)
8284 ERRMSG("Number of levels out of range!");
8285
8286 if (!ctl->dd) {
8287
8288 /* Get grid dimensions... */
8289 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
8290 LOG(2, "Number of longitudes: %d", met->nx);
8291
8292 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
8293 LOG(2, "Number of latitudes: %d", met->ny);
8294
8295 /* Read longitudes and latitudes... */
8296 NC_GET_DOUBLE("lon", met->lon, 1);
8297 LOG(2, "Longitudes: %g, %g ... %g deg",
8298 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
8299 NC_GET_DOUBLE("lat", met->lat, 1);
8300 LOG(2, "Latitudes: %g, %g ... %g deg",
8301 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
8302
8303 } else {
8304
8305 /* Use 'naive', i.e. equidistant lat-lon domain decomposition... */
8306 read_met_nc_grid_dd_naive(dd, ctl, met, ncid);
8307
8308 }
8309
8310 /* Read pressure levels... */
8311 if (ctl->met_np <= 0) {
8312 NC_GET_DOUBLE(levname, met->p, 1);
8313 for (int ip = 0; ip < met->np; ip++)
8314 met->p[ip] /= 100.;
8315 LOG(2, "Altitude levels: %g, %g ... %g km",
8316 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8317 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8318 met->p[0], met->p[1], met->p[met->np - 1]);
8319 }
8320
8321 /* Read hybrid levels... */
8322 if (strcasecmp(levname, "hybrid") == 0)
8323 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
8324
8325 /* Read model level coefficients from file... */
8326 if (ctl->met_vert_coord == 2) {
8327 NC_GET_DOUBLE("hyam", met->hyam, 1);
8328 NC_GET_DOUBLE("hybm", met->hybm, 1);
8329 }
8330
8331 /* Copy model level coefficients from control parameters... */
8332 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
8333 if (ctl->met_nlev <= 0)
8334 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
8335 for (int ip = 0; ip < ctl->met_nlev; ip++) {
8336 met->hyam[ip] = ctl->met_lev_hyam[ip];
8337 met->hybm[ip] = ctl->met_lev_hybm[ip];
8338 }
8339 }
8340
8341 /* Calculate eta levels... */
8342 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
8343 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
8344 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
8345 ERRMSG("Eta levels must be ascending!");
8346 }
8347
8348 /* Check horizontal grid spacing... */
8349 for (int ix = 2; ix < met->nx; ix++)
8350 if (fabs
8351 (fabs(met->lon[ix] - met->lon[ix - 1]) -
8352 fabs(met->lon[1] - met->lon[0])) > 0.001)
8353 ERRMSG("No regular grid spacing in longitudes!");
8354 for (int iy = 2; iy < met->ny; iy++)
8355 if (fabs
8356 (fabs(met->lat[iy] - met->lat[iy - 1]) -
8357 fabs(met->lat[1] - met->lat[0])) > 0.001) {
8358 WARN("No regular grid spacing in latitudes!");
8359 break;
8360 }
8361}
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:11113
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:9821
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:11212
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3573
double eta[EP]
Model level eta values.
Definition: mptrac.h:3582
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3576
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3579
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.

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

8369 {
8370
8371 /* Set timer... */
8372 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
8373 LOG(2, "Read surface data...");
8374
8375 /* Read surface pressure... */
8376 if (read_met_nc_2d
8377 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
8378 1.0f, 1)) {
8379 for (int ix = 0; ix < met->nx; ix++)
8380 for (int iy = 0; iy < met->ny; iy++)
8381 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8382 } else
8383 if (!read_met_nc_2d
8384 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
8385 0.01f, 1)) {
8386 WARN("Cannot not read surface pressure data (use lowest level)!");
8387 for (int ix = 0; ix < met->nx; ix++)
8388 for (int iy = 0; iy < met->ny; iy++)
8389 met->ps[ix][iy]
8390 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8391 }
8392
8393 /* MPTRAC meteo data... */
8394 if (ctl->met_clams == 0) {
8395
8396 /* Read geopotential height at the surface... */
8397 if (!read_met_nc_2d
8398 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8399 (float) (1. / (1000. * G0)), 1))
8400 if (!read_met_nc_2d
8401 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8402 (float) (1. / 1000.), 1))
8403 WARN("Cannot read surface geopotential height!");
8404 }
8405
8406 /* CLaMS meteo data... */
8407 else {
8408
8409 /* Read geopotential height at the surface
8410 (use lowermost level of 3-D data field)... */
8411 float *help;
8412 ALLOC(help, float,
8413 EX * EY * EP);
8414 memcpy(help, met->pl, sizeof(met->pl));
8415 if (!read_met_nc_3d
8416 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
8417 (float) (1e-3 / G0)))
8418 ERRMSG("Cannot read geopotential height!");
8419 for (int ix = 0; ix < met->nx; ix++)
8420 for (int iy = 0; iy < met->ny; iy++)
8421 met->zs[ix][iy] = met->pl[ix][iy][0];
8422 memcpy(met->pl, help, sizeof(met->pl));
8423 free(help);
8424 }
8425
8426 /* Read temperature at the surface... */
8427 if (!read_met_nc_2d
8428 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
8429 1))
8430 WARN("Cannot read surface temperature!");
8431
8432 /* Read zonal wind at the surface... */
8433 if (!read_met_nc_2d
8434 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
8435 met->us, 1.0, 1))
8436 WARN("Cannot read surface zonal wind!");
8437
8438 /* Read meridional wind at the surface... */
8439 if (!read_met_nc_2d
8440 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
8441 met->vs, 1.0, 1))
8442 WARN("Cannot read surface meridional wind!");
8443
8444 /* Read eastward turbulent surface stress... */
8445 if (!read_met_nc_2d
8446 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
8447 1.0, 1))
8448 WARN("Cannot read eastward turbulent surface stress!");
8449
8450 /* Read northward turbulent surface stress... */
8451 if (!read_met_nc_2d
8452 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
8453 1.0, 1))
8454 WARN("Cannot read nothward turbulent surface stress!");
8455
8456 /* Read surface sensible heat flux... */
8457 if (!read_met_nc_2d
8458 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
8459 1.0, 1))
8460 WARN("Cannot read surface sensible heat flux!");
8461
8462 /* Read land-sea mask... */
8463 if (!read_met_nc_2d
8464 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
8465 1.0, 1))
8466 WARN("Cannot read land-sea mask!");
8467
8468 /* Read sea surface temperature... */
8469 if (!read_met_nc_2d
8470 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
8471 1.0, 1))
8472 WARN("Cannot read sea surface temperature!");
8473
8474 /* Read PBL... */
8475 if (ctl->met_pbl == 0)
8476 if (!read_met_nc_2d
8477 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8478 0.01f, 1))
8479 WARN("Cannot read planetary boundary layer pressure!");
8480 if (ctl->met_pbl == 1)
8481 if (!read_met_nc_2d
8482 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8483 0.001f, 1))
8484 WARN("Cannot read planetary boundary layer height!");
8485
8486 /* Read CAPE... */
8487 if (ctl->met_cape == 0)
8488 if (!read_met_nc_2d
8489 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
8490 met->cape, 1.0, 1))
8491 WARN("Cannot read CAPE!");
8492
8493 /* Read CIN... */
8494 if (ctl->met_cape == 0)
8495 if (!read_met_nc_2d
8496 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
8497 1.0, 1))
8498 WARN("Cannot read convective inhibition!");
8499}
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:8700
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:8962
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.

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

8507 {
8508
8509 /* Set timer... */
8510 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT", NVTX_READ);
8511 LOG(2, "Read level data...");
8512
8513 /* Read temperature... */
8514 if (!read_met_nc_3d
8515 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
8516 ERRMSG("Cannot read temperature!");
8517
8518 /* Read horizontal wind and vertical velocity... */
8519 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
8520 ERRMSG("Cannot read zonal wind!");
8521 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
8522 ERRMSG("Cannot read meridional wind!");
8523 if (!read_met_nc_3d
8524 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
8525 WARN("Cannot read vertical velocity!");
8526
8527 /* Read water vapor... */
8528 if (!ctl->met_relhum) {
8529 if (!read_met_nc_3d
8530 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
8531 (float) (MA / MH2O)))
8532 WARN("Cannot read specific humidity!");
8533 } else {
8534 if (!read_met_nc_3d
8535 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
8536 WARN("Cannot read relative humidity!");
8537#pragma omp parallel for default(shared) collapse(2)
8538 for (int ix = 0; ix < met->nx; ix++)
8539 for (int iy = 0; iy < met->ny; iy++)
8540 for (int ip = 0; ip < met->np; ip++) {
8541 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
8542 met->h2o[ix][iy][ip] =
8543 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
8544 }
8545 }
8546
8547 /* Read ozone... */
8548 if (!read_met_nc_3d
8549 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
8550 (float) (MA / MO3)))
8551 WARN("Cannot read ozone data!");
8552
8553 /* Read cloud data... */
8554 if (!read_met_nc_3d
8555 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
8556 WARN("Cannot read cloud liquid water content!");
8557 if (!read_met_nc_3d
8558 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
8559 WARN("Cannot read cloud rain water content!");
8560 if (!read_met_nc_3d
8561 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
8562 WARN("Cannot read cloud ice water content!");
8563 if (!read_met_nc_3d
8564 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
8565 WARN("Cannot read cloud snow water content!");
8566 if (!read_met_nc_3d
8567 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
8568 WARN("Cannot read cloud cover!");
8569
8570 /* Read zeta and zeta_dot... */
8571 if (ctl->advect_vert_coord == 1) {
8572 if (!read_met_nc_3d
8573 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
8574 WARN("Cannot read ZETA!");
8575 if (!read_met_nc_3d
8576 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
8577 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
8578 WARN("Cannot read ZETA_DOT!");
8579 }
8580
8581 /* Read eta and eta_dot... */
8582 else if (ctl->advect_vert_coord == 3) {
8583#pragma omp parallel for default(shared)
8584 for (int ix = 0; ix < met->nx; ix++)
8585 for (int iy = 0; iy < met->ny; iy++)
8586 for (int ip = 0; ip < met->np; ip++)
8587 met->zetal[ix][iy][ip] =
8588 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
8589 if (!read_met_nc_3d
8590 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
8591 1.0))
8592 WARN("Cannot read eta vertical velocity!");
8593 }
8594
8595 /* Store velocities on model levels... */
8596 if (ctl->met_vert_coord != 0) {
8597#pragma omp parallel for default(shared)
8598 for (int ix = 0; ix < met->nx; ix++)
8599 for (int iy = 0; iy < met->ny; iy++)
8600 for (int ip = 0; ip < met->np; ip++) {
8601 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
8602 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
8603 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
8604 }
8605
8606 /* Save number of model levels... */
8607 met->npl = met->np;
8608 }
8609
8610 /* Get pressure on model levels... */
8611 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
8612
8613 /* Read 3-D pressure field... */
8614 if (ctl->met_vert_coord == 1) {
8615 if (!read_met_nc_3d
8616 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
8617 0.01f))
8618 if (!read_met_nc_3d
8619 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
8620 ERRMSG("Cannot read pressure on model levels!");
8621 }
8622
8623 /* Use a and b coefficients for full levels (at layer midpoints)... */
8624 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
8625
8626 /* Check number of levels... */
8627 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
8628 ERRMSG("Mismatch in number of model levels!");
8629
8630 /* Calculate pressure... */
8631 for (int ix = 0; ix < met->nx; ix++)
8632 for (int iy = 0; iy < met->ny; iy++)
8633 for (int ip = 0; ip < met->np; ip++)
8634 met->pl[ix][iy][ip] =
8635 (float) (met->hyam[ip] / 100. +
8636 met->hybm[ip] * met->ps[ix][iy]);
8637 }
8638
8639 /* Use a and b coefficients for half levels (at layer interfaces)... */
8640 else if (ctl->met_vert_coord == 4) {
8641
8642 /* Check number of levels... */
8643 if (met->np + 1 != ctl->met_nlev)
8644 ERRMSG("Mismatch in number of model levels!");
8645
8646 /* Calculate pressure... */
8647#pragma omp parallel for default(shared) collapse(2)
8648 for (int ix = 0; ix < met->nx; ix++)
8649 for (int iy = 0; iy < met->ny; iy++)
8650 for (int ip = 0; ip < met->np; ip++) {
8651 const double p0 =
8652 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
8653 const double p1 =
8654 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
8655 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
8656 }
8657 }
8658
8659 /* Check ordering of pressure levels... */
8660 for (int ix = 0; ix < met->nx; ix++)
8661 for (int iy = 0; iy < met->ny; iy++)
8662 for (int ip = 1; ip < met->np; ip++)
8663 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
8664 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
8665 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
8666 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
8667 ERRMSG("Pressure profiles are not monotonic!");
8668 }
8669
8670 /* Interpolate from model levels to pressure levels... */
8671 if (ctl->met_np > 0) {
8672
8673 /* Interpolate variables... */
8674 read_met_ml2pl(ctl, met, met->t, "T");
8675 read_met_ml2pl(ctl, met, met->u, "U");
8676 read_met_ml2pl(ctl, met, met->v, "V");
8677 read_met_ml2pl(ctl, met, met->w, "W");
8678 read_met_ml2pl(ctl, met, met->h2o, "H2O");
8679 read_met_ml2pl(ctl, met, met->o3, "O3");
8680 read_met_ml2pl(ctl, met, met->lwc, "LWC");
8681 read_met_ml2pl(ctl, met, met->rwc, "RWC");
8682 read_met_ml2pl(ctl, met, met->iwc, "IWC");
8683 read_met_ml2pl(ctl, met, met->swc, "SWC");
8684 read_met_ml2pl(ctl, met, met->cc, "CC");
8685
8686 /* Set new pressure levels... */
8687 met->np = ctl->met_np;
8688 for (int ip = 0; ip < met->np; ip++)
8689 met->p[ip] = ctl->met_p[ip];
8690 }
8691
8692 /* Check ordering of pressure levels... */
8693 for (int ip = 1; ip < met->np; ip++)
8694 if (met->p[ip - 1] < met->p[ip])
8695 ERRMSG("Pressure levels must be descending!");
8696}
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:9654
#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).
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.
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 8700 of file mptrac.c.

8713 {
8714
8715 char varsel[LEN];
8716
8717 float offset, scalfac;
8718
8719 int varid;
8720
8721 /* Check if variable exists... */
8722 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8723 sprintf(varsel, "%s", varname);
8724 else if (varname2 != NULL
8725 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8726 sprintf(varsel, "%s", varname2);
8727 else if (varname3 != NULL
8728 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8729 sprintf(varsel, "%s", varname3);
8730 else if (varname4 != NULL
8731 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8732 sprintf(varsel, "%s", varname4);
8733 else if (varname5 != NULL
8734 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
8735 sprintf(varsel, "%s", varname5);
8736 else if (varname6 != NULL
8737 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
8738 sprintf(varsel, "%s", varname6);
8739 else
8740 return 0;
8741
8742 /* Read packed data... */
8743 if (ctl->met_nc_scale && !ctl->dd
8744 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8745 && nc_get_att_float(ncid, varid, "scale_factor",
8746 &scalfac) == NC_NOERR) {
8747
8748 /* Allocate... */
8749 short *help;
8750 ALLOC(help, short,
8751 EX * EY * EP);
8752
8753 /* Read fill value and missing value... */
8754 short fillval, missval;
8755 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8756 fillval = 0;
8757 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
8758 missval = 0;
8759
8760 /* Write info... */
8761 LOG(2, "Read 2-D variable: %s"
8762 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
8763 varsel, fillval, missval, scalfac, offset);
8764
8765 /* Read data... */
8766 NC(nc_get_var_short(ncid, varid, help));
8767
8768 /* Check meteo data layout... */
8769 if (ctl->met_convention != 0)
8770 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
8771
8772 /* Copy and check data... */
8773 omp_set_dynamic(1);
8774#pragma omp parallel for default(shared)
8775 for (int ix = 0; ix < met->nx; ix++)
8776 for (int iy = 0; iy < met->ny; iy++) {
8777 if (init)
8778 dest[ix][iy] = 0;
8779 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
8780 if ((fillval == 0 || aux != fillval)
8781 && (missval == 0 || aux != missval)
8782 && fabsf(aux * scalfac + offset) < 1e14f)
8783 dest[ix][iy] += scl * (aux * scalfac + offset);
8784 else
8785 dest[ix][iy] = NAN;
8786 }
8787 omp_set_dynamic(0);
8788
8789 /* Free... */
8790 free(help);
8791 }
8792
8793 /* Unpacked data... */
8794 else if (!ctl->dd) {
8795
8796 /* Allocate... */
8797 float *help;
8798 ALLOC(help, float,
8799 EX * EY);
8800
8801 /* Read fill value and missing value... */
8802 float fillval, missval;
8803 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8804 fillval = 0;
8805 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8806 missval = 0;
8807
8808 /* Write info... */
8809 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8810 varsel, fillval, missval);
8811
8812 /* Read data... */
8813 NC(nc_get_var_float(ncid, varid, help));
8814
8815 /* Check meteo data layout... */
8816 if (ctl->met_convention == 0) {
8817
8818 /* Copy and check data (ordering: lat, lon)... */
8819 omp_set_dynamic(1);
8820#pragma omp parallel for default(shared)
8821 for (int ix = 0; ix < met->nx; ix++)
8822 for (int iy = 0; iy < met->ny; iy++) {
8823 if (init)
8824 dest[ix][iy] = 0;
8825 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
8826 if ((fillval == 0 || aux != fillval)
8827 && (missval == 0 || aux != missval)
8828 && fabsf(aux) < 1e14f)
8829 dest[ix][iy] += scl * aux;
8830 else
8831 dest[ix][iy] = NAN;
8832 }
8833 omp_set_dynamic(0);
8834
8835 } else {
8836
8837 /* Copy and check data (ordering: lon, lat)... */
8838 omp_set_dynamic(1);
8839#pragma omp parallel for default(shared)
8840 for (int iy = 0; iy < met->ny; iy++)
8841 for (int ix = 0; ix < met->nx; ix++) {
8842 if (init)
8843 dest[ix][iy] = 0;
8844 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
8845 if ((fillval == 0 || aux != fillval)
8846 && (missval == 0 || aux != missval)
8847 && fabsf(aux) < 1e14f)
8848 dest[ix][iy] += scl * aux;
8849 else
8850 dest[ix][iy] = NAN;
8851 }
8852 omp_set_dynamic(0);
8853 }
8854
8855 /* Free... */
8856 free(help);
8857
8858 }
8859 /* Domain decomposed data... */
8860 else {
8861
8862 /* Read fill value and missing value... */
8863 float fillval, missval;
8864 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8865 fillval = 0;
8866 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8867 missval = 0;
8868
8869 /* Write info... */
8870 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8871 varsel, fillval, missval);
8872
8873 /* Define hyperslab... */
8874 float *help;
8875 size_t help_subdomain_start[3];
8876 size_t help_subdomain_count[3];
8877
8878 help_subdomain_start[0] = 0;
8879 help_subdomain_start[1] = dd->subdomain_start[2];
8880 help_subdomain_start[2] = dd->subdomain_start[3];
8881
8882 help_subdomain_count[0] = 1;
8883 help_subdomain_count[1] = dd->subdomain_count[2]; //y
8884 help_subdomain_count[2] = dd->subdomain_count[3]; //x
8885
8886 ALLOC(help, float,
8887 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]
8888 );
8889
8890 /* Read data... */
8891 NC(nc_get_vara_float
8892 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
8893
8894 /* Read halos at boundaries... */
8895 size_t help_halo_bnd_start[3];
8896 size_t help_halo_bnd_count[3];
8897
8898 help_halo_bnd_start[0] = 0;
8899 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
8900 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
8901
8902 help_halo_bnd_count[0] = 1;
8903 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
8904 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
8905
8906 float *help_halo;
8907 ALLOC(help_halo, float,
8908 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
8909 NC(nc_get_vara_float
8910 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
8911
8912 /* Check meteo data layout... */
8913 if (ctl->met_convention == 0) {
8914 /* Copy and check data (ordering: lat, lon)... */
8915#pragma omp parallel for default(shared) num_threads(12)
8916 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
8917 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
8918 if (init == 1)
8919 dest[ix + dd->halo_offset_start][iy] = 0;
8920 const float aux =
8921 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
8922 if ((fillval == 0 || aux != fillval)
8923 && (missval == 0 || aux != missval)
8924 && fabsf(aux) < 1e14f) {
8925 dest[ix + dd->halo_offset_start][iy] += scl * aux;
8926 } else
8927 dest[ix + dd->halo_offset_start][iy] = NAN;
8928 }
8929
8930 /* Copy and check data (ordering: lat, lon)... */
8931#pragma omp parallel for default(shared) num_threads(12)
8932 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
8933 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
8934 if (init == 1)
8935 dest[ix + dd->halo_offset_end][iy] = 0;
8936 const float aux =
8937 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
8938 if ((fillval == 0 || aux != fillval)
8939 && (missval == 0 || aux != missval)
8940 && fabsf(aux) < 1e14f)
8941 dest[ix + dd->halo_offset_end][iy] += scl * aux;
8942 else {
8943 dest[ix + dd->halo_offset_end][iy] = NAN;
8944 }
8945 }
8946
8947 } else {
8948 ERRMSG("Domain decomposition with data convection incompatible!");
8949 }
8950
8951 /* Free... */
8952 free(help);
8953 free(help_halo);
8954 }
8955
8956 /* Return... */
8957 return 1;
8958}
size_t halo_bnd_count[4]
Hyperslab of boundary halos count.
Definition: mptrac.h:3766
int halo_offset_end
Hyperslab of boundary halos count.
Definition: mptrac.h:3772
size_t halo_bnd_start[4]
Hyperslab of boundary halos start.
Definition: mptrac.h:3763
int halo_offset_start
Hyperslab of boundary halos count.
Definition: mptrac.h:3769
size_t subdomain_count[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3760
size_t subdomain_start[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3757

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

8972 {
8973
8974 SELECT_TIMER("read_met_nc_3d", "INPUT", NVTX_READ);
8975
8976 char varsel[LEN];
8977
8978 float offset, scalfac;
8979
8980 int varid;
8981
8982 /* Check if variable exists... */
8983 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8984 sprintf(varsel, "%s", varname);
8985 else if (varname2 != NULL
8986 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8987 sprintf(varsel, "%s", varname2);
8988 else if (varname3 != NULL
8989 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8990 sprintf(varsel, "%s", varname3);
8991 else if (varname4 != NULL
8992 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8993 sprintf(varsel, "%s", varname4);
8994 else
8995 return 0;
8996
8997 if (ctl->met_nc_scale && !ctl->dd
8998 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8999 && nc_get_att_float(ncid, varid, "scale_factor",
9000 &scalfac) == NC_NOERR) {
9001
9002 /* Allocate... */
9003 short *help;
9004 ALLOC(help, short,
9005 EX * EY * EP);
9006
9007 /* Read fill value and missing value... */
9008 short fillval, missval;
9009 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9010 fillval = 0;
9011 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9012 missval = 0;
9013
9014 /* Write info... */
9015 LOG(2, "Read 3-D variable: %s "
9016 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9017 varsel, fillval, missval, scalfac, offset);
9018
9019 /* Read data... */
9020 NC(nc_get_var_short(ncid, varid, help));
9021
9022 /* Check meteo data layout... */
9023 if (ctl->met_convention != 0)
9024 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9025
9026 /* Copy and check data... */
9027 omp_set_dynamic(1);
9028#pragma omp parallel for default(shared)
9029 for (int ix = 0; ix < met->nx; ix++)
9030 for (int iy = 0; iy < met->ny; iy++)
9031 for (int ip = 0; ip < met->np; ip++) {
9032 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9033 if ((fillval == 0 || aux != fillval)
9034 && (missval == 0 || aux != missval)
9035 && fabsf(aux * scalfac + offset) < 1e14f)
9036 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
9037 else
9038 dest[ix][iy][ip] = NAN;
9039 }
9040 omp_set_dynamic(0);
9041
9042 /* Free... */
9043 free(help);
9044 }
9045
9046 /* Unpacked data... */
9047 else if (!ctl->dd) {
9048
9049 /* Allocate... */
9050 float *help;
9051 ALLOC(help, float,
9052 EX * EY * EP);
9053
9054 /* Read fill value and missing value... */
9055 float fillval, missval;
9056 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9057 fillval = 0;
9058 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9059 missval = 0;
9060
9061 /* Write info... */
9062 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9063 varsel, fillval, missval);
9064
9065 /* Read data... */
9066 NC(nc_get_var_float(ncid, varid, help));
9067
9068 /* Check meteo data layout... */
9069 if (ctl->met_convention == 0) {
9070
9071 /* Copy and check data (ordering: lev, lat, lon)... */
9072 omp_set_dynamic(1);
9073#pragma omp parallel for default(shared)
9074 for (int ix = 0; ix < met->nx; ix++)
9075 for (int iy = 0; iy < met->ny; iy++)
9076 for (int ip = 0; ip < met->np; ip++) {
9077 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9078 if ((fillval == 0 || aux != fillval)
9079 && (missval == 0 || aux != missval)
9080 && fabsf(aux) < 1e14f)
9081 dest[ix][iy][ip] = scl * aux;
9082 else
9083 dest[ix][iy][ip] = NAN;
9084 }
9085 omp_set_dynamic(0);
9086
9087 } else {
9088
9089 /* Copy and check data (ordering: lon, lat, lev)... */
9090 omp_set_dynamic(1);
9091#pragma omp parallel for default(shared)
9092 for (int ip = 0; ip < met->np; ip++)
9093 for (int iy = 0; iy < met->ny; iy++)
9094 for (int ix = 0; ix < met->nx; ix++) {
9095 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9096 if ((fillval == 0 || aux != fillval)
9097 && (missval == 0 || aux != missval)
9098 && fabsf(aux) < 1e14f)
9099 dest[ix][iy][ip] = scl * aux;
9100 else
9101 dest[ix][iy][ip] = NAN;
9102 }
9103 omp_set_dynamic(0);
9104 }
9105
9106 /* Free... */
9107 free(help);
9108
9109 }
9110 /* Domain decomposed data... */
9111 else {
9112
9113 /* Read fill value and missing value... */
9114 float fillval, missval;
9115 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9116 fillval = 0;
9117 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9118 missval = 0;
9119
9120 /* Write info... */
9121 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9122 varsel, fillval, missval);
9123
9124 SELECT_TIMER("read_met_nc_3d_CP1", "INPUT", NVTX_READ);
9125
9126 /* Define hyperslab... */
9127
9128 /* Allocate... */
9129 float *help;
9130 ALLOC(help, float,
9131 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
9132 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
9133
9134 SELECT_TIMER("read_met_nc_3d_CP2", "INPUT", NVTX_READ);
9135
9136 /* Use default NetCDF parallel I/O behavior */
9137 NC(nc_get_vara_float
9138 (ncid, varid, dd->subdomain_start, dd->subdomain_count, help));
9139
9140 /* Read halos separately at boundaries... */
9141 float *help_halo;
9142 ALLOC(help_halo, float,
9143 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
9144 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
9145
9146 SELECT_TIMER("read_met_nc_3d_CP3", "INPUT", NVTX_READ);
9147
9148 /* Halo read also uses independent access */
9149 NC(nc_get_vara_float(ncid,
9150 varid,
9151 dd->halo_bnd_start, dd->halo_bnd_count, help_halo));
9152
9153 SELECT_TIMER("read_met_nc_3d_CP4", "INPUT", NVTX_READ);
9154
9155 /* Check meteo data layout... */
9156 if (ctl->met_convention == 0) {
9157 /* Copy and check data (ordering: lev, lat, lon)... */
9158#pragma omp parallel for default(shared) num_threads(12)
9159 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9160 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9161 for (int ip = 0; ip < met->np; ip++) {
9162 const float aux =
9163 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
9164 (int) dd->subdomain_count[3])];
9165 if ((fillval == 0 || aux != fillval)
9166 && (missval == 0 || aux != missval)
9167 && fabsf(aux) < 1e14f)
9168 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9169 else
9170 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9171 }
9172
9173#pragma omp parallel for default(shared) num_threads(12)
9174 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9175 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9176 for (int ip = 0; ip < met->np; ip++) {
9177 const float aux =
9178 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
9179 (int) dd->halo_bnd_count[3])];
9180 if ((fillval == 0 || aux != fillval)
9181 && (missval == 0 || aux != missval)
9182 && fabsf(aux) < 1e14f)
9183 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9184 else
9185 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9186 }
9187
9188 } else {
9189
9190 /* Copy and check data (ordering: lon, lat, lev)... */
9191#pragma omp parallel for default(shared) num_threads(12)
9192 for (int ip = 0; ip < met->np; ip++)
9193 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9194 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
9195 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9196 if ((fillval == 0 || aux != fillval)
9197 && (missval == 0 || aux != missval)
9198 && fabsf(aux) < 1e14f)
9199 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9200 else
9201 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9202 }
9203
9204#pragma omp parallel for default(shared) num_threads(12)
9205 for (int ip = 0; ip < met->np; ip++)
9206 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9207 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
9208 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9209 if ((fillval == 0 || aux != fillval)
9210 && (missval == 0 || aux != missval)
9211 && fabsf(aux) < 1e14f)
9212 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9213 else
9214 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9215 }
9216 }
9217
9218 /* Free... */
9219 free(help);
9220 free(help_halo);
9221 }
9222
9223 /* Return... */
9224 return 1;
9225}

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

9658 {
9659
9660 double aux[EP], p[EP];
9661
9662 /* Set timer... */
9663 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
9664 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
9665
9666 /* Loop over columns... */
9667#pragma omp parallel for default(shared) private(aux,p) collapse(2)
9668 for (int ix = 0; ix < met->nx; ix++)
9669 for (int iy = 0; iy < met->ny; iy++) {
9670
9671 /* Copy pressure profile... */
9672 for (int ip = 0; ip < met->np; ip++)
9673 p[ip] = met->pl[ix][iy][ip];
9674
9675 /* Interpolate... */
9676 for (int ip = 0; ip < ctl->met_np; ip++) {
9677 double pt = ctl->met_p[ip];
9678 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
9679 pt = p[0];
9680 else if ((pt > p[met->np - 1] && p[1] > p[0])
9681 || (pt < p[met->np - 1] && p[1] < p[0]))
9682 pt = p[met->np - 1];
9683 const int ip2 = locate_irr(p, met->np, pt);
9684 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
9685 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
9686 }
9687
9688 /* Copy data... */
9689 for (int ip = 0; ip < ctl->met_np; ip++)
9690 var[ix][iy][ip] = (float) aux[ip];
9691 }
9692}
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 9696 of file mptrac.c.

9698 {
9699
9700 /* Check parameters... */
9701 if (ctl->advect_vert_coord != 1)
9702 return;
9703
9704 /* Set timer... */
9705 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
9706 LOG(2, "Make zeta profiles monotone...");
9707
9708 /* Create monotone zeta profiles... */
9709#pragma omp parallel for default(shared) collapse(2)
9710 for (int i = 0; i < met->nx; i++)
9711 for (int j = 0; j < met->ny; j++) {
9712 int k = 1;
9713
9714 while (k < met->npl) { /* Check if there is an inversion at level k... */
9715 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
9716 /* Find the upper level k+l over the inversion... */
9717 int l = 0;
9718 do {
9719 l++;
9720 }
9721 while ((met->zetal[i][j][k - 1] >=
9722 met->zetal[i][j][k + l]) & (k + l < met->npl));
9723
9724 /* Interpolate linear between the top and bottom
9725 of the inversion... */
9726 float s =
9727 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
9728 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9729
9730 for (int m = k; m < k + l; m++) {
9731 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9732 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
9733 }
9734
9735 /* Search for more inversions above the last inversion ... */
9736 k = k + l;
9737 } else {
9738 k++;
9739 }
9740 }
9741 }
9742
9743 /* Create monotone pressure profiles... */
9744#pragma omp parallel for default(shared) collapse(2)
9745 for (int i = 0; i < met->nx; i++)
9746 for (int j = 0; j < met->ny; j++) {
9747 int k = 1;
9748
9749 while (k < met->npl) { /* Check if there is an inversion at level k... */
9750 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
9751
9752 /* Find the upper level k+l over the inversion... */
9753 int l = 0;
9754 do {
9755 l++;
9756 }
9757 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
9758 met->npl));
9759
9760 /* Interpolate linear between the top and bottom
9761 of the inversion... */
9762 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
9763 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9764
9765 for (int m = k; m < k + l; m++) {
9766 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9767 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
9768 }
9769
9770 /* Search for more inversions above the last inversion ... */
9771 k += l;
9772 } else {
9773 k++;
9774 }
9775 }
9776 }
9777}

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

9785 {
9786
9787 int ncid;
9788
9789 /* Open file... */
9790#ifdef DD
9791 if (ctl->dd) {
9792 NC(nc_open_par
9793 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
9794 &ncid))
9795 }
9796#else
9797 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
9798 WARN("Cannot open file!");
9799 return 0;
9800 }
9801#endif
9802
9803 /* Read coordinates of meteo data... */
9804 read_met_nc_grid(filename, ncid, ctl, met, dd);
9805
9806 /* Read surface data... */
9807 read_met_nc_surface(ncid, ctl, met, dd);
9808
9809 /* Read meteo data on vertical levels... */
9810 read_met_nc_levels(ncid, ctl, met, dd);
9811
9812 /* Close file... */
9813 NC(nc_close(ncid));
9814
9815 /* Return success... */
9816 return 1;
9817}
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:8503
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:8365
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:8198
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 9821 of file mptrac.c.

9825 {
9826
9827 int varid;
9828
9829 /* Get the MPI information... */
9830#ifdef MPI
9831 MPI_Comm_rank(MPI_COMM_WORLD, &dd->rank);
9832 MPI_Comm_size(MPI_COMM_WORLD, &dd->size);
9833#endif
9834
9835 int help_nx_glob;
9836 int help_ny_glob;
9837
9838 /* Get grid dimensions... */
9839 NC_INQ_DIM("lon", &help_nx_glob, 0, 0, 0);
9840 LOG(2, "Number of longitudes: %d", help_nx_glob);
9841 met->nx = (int) floor(help_nx_glob / ctl->dd_subdomains_zonal);
9842
9843 NC_INQ_DIM("lat", &help_ny_glob, 0, 0, 0);
9844 LOG(2, "Number of latitudes: %d", help_ny_glob);
9845 met->ny = (int) floor(help_ny_glob / ctl->dd_subdomains_meridional);
9846
9847 double *help_lon_glob;
9848 double *help_lat_glob;
9849 ALLOC(help_lon_glob, double,
9850 help_nx_glob);
9851 ALLOC(help_lat_glob, double,
9852 help_ny_glob);
9853
9854 /* Read global longitudes and latitudes... */
9855 NC_GET_DOUBLE("lon", help_lon_glob, 1);
9856 LOG(2, "Longitudes: %g, %g ... %g deg",
9857 help_lon_glob[0], help_lon_glob[1], help_lon_glob[help_nx_glob - 1]);
9858 NC_GET_DOUBLE("lat", help_lat_glob, 1);
9859 LOG(2, "Latitudes: %g, %g ... %g deg",
9860 help_lat_glob[0], help_lat_glob[1], help_lat_glob[help_ny_glob - 1]);
9861
9862 /* Determine hyperslabs for reading the data in parallel... */
9863
9864 /* Check for edge cases... */
9865 int left = (dd->rank <= ctl->dd_subdomains_meridional - 1);
9866 int right = (dd->rank >= dd->size - ctl->dd_subdomains_meridional);
9867 int top = (dd->rank % ctl->dd_subdomains_meridional == 0);
9868 int bottom =
9869 (dd->rank % ctl->dd_subdomains_meridional ==
9870 ctl->dd_subdomains_meridional - 1);
9871
9872 /* Set the hyperslab for the subdomain... */
9873 dd->subdomain_start[0] = 0;
9874 dd->subdomain_start[1] = 0;
9875 dd->subdomain_start[2] =
9876 (size_t) ((dd->rank % ctl->dd_subdomains_meridional) * met->ny);
9877 dd->subdomain_start[3] =
9878 (size_t) (floor(dd->rank / ctl->dd_subdomains_meridional) * met->nx);
9879
9880 /* Extend subdomains at the right and bottom to fit the full domain. */
9881 if (right) {
9882 int gap = help_nx_glob - ctl->dd_subdomains_zonal * met->nx;
9883 if (gap > 0) {
9884 met->nx = met->nx + gap;
9885 WARN("Extended subdomains at the right to fit to full domain.");
9886 }
9887 }
9888 if (bottom) {
9889 int gap = help_ny_glob - ctl->dd_subdomains_meridional * met->ny;
9890 if (gap > 0) {
9891 met->ny = met->ny + gap;
9892 WARN("Extended subdomains at the bottom to fit to full domain.");
9893 }
9894 }
9895
9896 /* Block-size, i.e. count */
9897 dd->subdomain_count[0] = 1;
9898 dd->subdomain_count[1] = (size_t) met->np;
9899 dd->subdomain_count[2] = (size_t) met->ny;
9900 dd->subdomain_count[3] = (size_t) met->nx;
9901
9902 /* Create halos and include them into the subdomain... */
9903 if (!left && !right) {
9904 // If we are not at the left or right edge extend in zonal direction...
9905 // Move the start one point to the left...
9906 dd->subdomain_count[3] =
9907 dd->subdomain_count[3] + (size_t) (ctl->dd_halos_size * 2);
9908 dd->subdomain_start[3] =
9909 dd->subdomain_start[3] - (size_t) ctl->dd_halos_size;
9910 } else {
9911 // If we are at the left or right edge, extend only in one zonal direction...
9912 dd->subdomain_count[3] =
9913 dd->subdomain_count[3] + (size_t) ctl->dd_halos_size;
9914 if (!left)
9915 // If we are not at the left edge, move the start to the left...
9916 dd->subdomain_start[3] =
9917 dd->subdomain_start[3] - (size_t) ctl->dd_halos_size;
9918 }
9919
9920 if (!top && !bottom) {
9921 // If we are not at the upper or lower edge extend in meridional direction...
9922 // Move the start point one point down...
9923 dd->subdomain_count[2] =
9924 dd->subdomain_count[2] + (size_t) (ctl->dd_halos_size * 2);
9925 dd->subdomain_start[2] =
9926 dd->subdomain_start[2] - (size_t) ctl->dd_halos_size;
9927 } else {
9928 // If we are at the top or the lower edge only extend in one mer. direction...
9929 dd->subdomain_count[2] =
9930 dd->subdomain_count[2] + (size_t) ctl->dd_halos_size;
9931 if (!top)
9932 // If we are not at the top, move the start one upward...
9933 dd->subdomain_start[2] =
9934 dd->subdomain_start[2] - (size_t) ctl->dd_halos_size;
9935 }
9936
9937 /* Set boundary halo hyperslabs ... */
9938 double lon_shift = 0;
9939 if (left || right) {
9940
9941 met->nx = met->nx + ctl->dd_halos_size;
9942
9943 dd->halo_bnd_start[0] = 0;
9944 dd->halo_bnd_start[1] = 0;
9945 dd->halo_bnd_start[3] = (size_t) (left ? (help_nx_glob - ctl->dd_halos_size) : (0)); //x
9946 dd->halo_bnd_start[2] = dd->subdomain_start[2]; //y
9947
9948 dd->halo_bnd_count[0] = 1;
9949 dd->halo_bnd_count[1] = (size_t) met->np;
9950 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
9951 dd->halo_bnd_count[2] =
9952 (size_t) met->ny +
9953 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
9954
9955 dd->halo_offset_start = (left ? (int) dd->halo_bnd_count[3] : 0);
9956 dd->halo_offset_end = (left ? 0 : (int) dd->subdomain_count[3]);
9957 lon_shift = (left ? -360 : 360);
9958
9959 } else {
9960
9961 dd->halo_bnd_start[0] = 0;
9962 dd->halo_bnd_start[1] = 0;
9963 dd->halo_bnd_start[3] = 0;
9964 dd->halo_bnd_start[2] = 0;
9965
9966 dd->halo_bnd_count[0] = 0;
9967 dd->halo_bnd_count[1] = 0;
9968 dd->halo_bnd_count[3] = 0;
9969 dd->halo_bnd_count[2] = 0;
9970 }
9971
9972 /* Get the range of the entire meteodata... */
9973 /* Handle both periodic (global) and non-periodic (regional) longitude grids */
9974 double lon_range = 360;
9975 //if (dd_is_periodic_longitude(met, help_nx_glob)) {
9976 /* For global grids with periodic boundaries, use full 360 degrees */
9977 //lon_range = 360.0;
9978 //LOG(3, "Detected periodic longitude boundaries, using lon_range = 360.0");
9979 //} else {
9980 /* For regional grids, use the actual data range */
9981 //lon_range = help_lon_glob[help_nx_glob - 1] - help_lon_glob[0];
9982 //LOG(3, "Detected non-periodic longitude boundaries, using lon_range = %g", lon_range);
9983 //}
9984
9985 double lat_range = help_lat_glob[help_ny_glob - 1] - help_lat_glob[0];
9986
9987 /* Focus on subdomain latitudes and longitudes... */
9988 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9989 met->lat[iy] = help_lat_glob[(int) dd->subdomain_start[2] + iy];
9990
9991 /* Focus on subdomain longitudes... */
9992 /* Keep space at the beginning or end of the array for halo... */
9993 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9994 met->lon[ix + dd->halo_offset_start] =
9995 help_lon_glob[(int) dd->subdomain_start[3] + ix];
9996
9997 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9998 met->lon[ix + dd->halo_offset_end] =
9999 help_lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
10000
10001 /* Reset the grid dimensions... */
10002 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
10003 met->ny = (int) dd->subdomain_count[2];
10004
10005 /* Determine subdomain edges... */
10006 dd->subdomain_lon_min = floor(dd->rank / ctl->dd_subdomains_meridional)
10007 * (lon_range) / (double) ctl->dd_subdomains_zonal;
10008 dd->subdomain_lon_max = dd->subdomain_lon_min
10009 + (lon_range) / (double) ctl->dd_subdomains_zonal;
10010
10011 /* Latitudes in descending order (90 to -90) */
10012 if (lat_range < 0) {
10013 dd->subdomain_lat_max = 90 + (dd->rank % ctl->dd_subdomains_meridional)
10014 * (lat_range) / (double) ctl->dd_subdomains_meridional;
10016 + (lat_range) / (double) ctl->dd_subdomains_meridional;
10017 } else {
10018 WARN
10019 ("lat_range > 0, but is expected to be negative, i.e. latitudes should range from 90 to -90")
10020 dd->subdomain_lat_min = -90 + (dd->rank % ctl->dd_subdomains_meridional)
10021 * (lat_range) / (double) ctl->dd_subdomains_meridional;
10022 dd->subdomain_lat_max = dd->subdomain_lat_min
10023 + (lat_range) / (double) ctl->dd_subdomains_meridional;
10024 }
10025
10026 LOG(2, "Total longitude range: %g deg", lon_range);
10027 LOG(2, "Total latitude range: %g deg", lat_range);
10028
10029 LOG(2, "Define subdomain properties.");
10030 LOG(2, "MPI information: Rank %d, Size %d", dd->rank, dd->size);
10031 LOG(2, "Edge position: l=%d,r=%d,t=%d, b=%d", (int) left, (int) right,
10032 (int) top, (int) bottom);
10033 LOG(2, "Sizes for limits: EX %d EY %d EP %d", EX, EY, EP);
10034 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d", met->nx,
10035 met->ny, met->np);
10036 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
10037 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
10038 (int) dd->halo_bnd_count[1]);
10039 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
10040 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
10041 (int) dd->subdomain_count[1]);
10042 LOG(2, "Subdomain start: nx %ld ny %ld np %ld", dd->subdomain_start[3],
10043 dd->subdomain_start[2], dd->subdomain_start[1]);
10044 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld", dd->halo_bnd_start[3],
10045 dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
10046 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
10047
10048 LOG(2, " %d Subdomain longitudes: %g, %g ... %g deg (edges: %g to %g)",
10049 dd->rank, met->lon[0], met->lon[1], met->lon[met->nx - 1],
10050 dd->subdomain_lon_min, dd->subdomain_lon_max);
10051 LOG(2, " %d Subdomain latitudes: %g, %g ... %g deg (edges: %g to %g)",
10052 dd->rank, met->lat[0], met->lat[1], met->lat[met->ny - 1],
10053 dd->subdomain_lat_min, dd->subdomain_lat_max);
10054
10055 free(help_lon_glob);
10056 free(help_lat_glob);
10057}
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3280
int rank
Rank of node.
Definition: mptrac.h:3727
double subdomain_lat_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3751
int size
Size of node.
Definition: mptrac.h:3730
double subdomain_lat_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3754

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

10063 {
10064
10065 /* Set timer... */
10066 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
10067 LOG(2, "Calculate planetary boundary layer...");
10068
10069 /* Convert PBL height from meteo file to pressure... */
10070 if (ctl->met_pbl == 1) {
10071
10072 /* Loop over grid points... */
10073#pragma omp parallel for default(shared) collapse(2)
10074 for (int ix = 0; ix < met->nx; ix++)
10075 for (int iy = 0; iy < met->ny; iy++) {
10076
10077 /* Get pressure at top of PBL... */
10078 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
10079 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
10080 met->pbl[ix][iy] =
10081 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
10082 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
10083 }
10084 }
10085
10086 /* Determine PBL based on Richardson number... */
10087 else if (ctl->met_pbl == 2) {
10088
10089 /* Parameters used to estimate the height of the PBL
10090 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
10091 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
10092
10093 /* Loop over grid points... */
10094#pragma omp parallel for default(shared) collapse(2)
10095 for (int ix = 0; ix < met->nx; ix++)
10096 for (int iy = 0; iy < met->ny; iy++) {
10097
10098 /* Set bottom level of PBL... */
10099 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
10100
10101 /* Find lowest level near the bottom... */
10102 int ip;
10103 for (ip = 1; ip < met->np; ip++)
10104 if (met->p[ip] < pbl_bot)
10105 break;
10106
10107 /* Get near surface data... */
10108 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
10109 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
10110 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
10111
10112 /* Init... */
10113 double rib_old = 0;
10114
10115 /* Loop over levels... */
10116 for (; ip < met->np; ip++) {
10117
10118 /* Get squared horizontal wind speed... */
10119 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
10120 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
10121 vh2 = MAX(vh2, SQR(umin));
10122
10123 /* Calculate bulk Richardson number... */
10124 const double rib =
10125 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
10126 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
10127 met->h2o[ix][iy][ip]) - tvs) / vh2;
10128
10129 /* Check for critical value... */
10130 if (rib >= rib_crit) {
10131 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
10132 rib, met->p[ip], rib_crit));
10133 if (met->pbl[ix][iy] > pbl_bot)
10134 met->pbl[ix][iy] = (float) pbl_bot;
10135 break;
10136 }
10137
10138 /* Save Richardson number... */
10139 rib_old = rib;
10140 }
10141 }
10142 }
10143
10144 /* Determine PBL based on potential temperature... */
10145 if (ctl->met_pbl == 3) {
10146
10147 /* Parameters used to estimate the height of the PBL
10148 (following HYSPLIT model)... */
10149 const double dtheta = 2.0, zmin = 0.1;
10150
10151 /* Loop over grid points... */
10152#pragma omp parallel for default(shared) collapse(2)
10153 for (int ix = 0; ix < met->nx; ix++)
10154 for (int iy = 0; iy < met->ny; iy++) {
10155
10156 /* Potential temperature at the surface... */
10157 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
10158
10159 /* Find topmost level where theta exceeds surface value by 2 K... */
10160 int ip;
10161 for (ip = met->np - 2; ip > 0; ip--)
10162 if (met->p[ip] >= 300.)
10163 if (met->p[ip] > met->ps[ix][iy]
10164 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
10165 break;
10166
10167 /* Interpolate... */
10168 met->pbl[ix][iy]
10169 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
10170 met->p[ip + 1],
10171 THETA(met->p[ip], met->t[ix][iy][ip]),
10172 met->p[ip], theta0 + dtheta));
10173
10174 /* Check minimum value... */
10175 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
10176 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
10177 met->pbl[ix][iy] = (float) pbl_min;
10178 }
10179 }
10180
10181 /* Loop over grid points... */
10182#pragma omp parallel for default(shared) collapse(2)
10183 for (int ix = 0; ix < met->nx; ix++)
10184 for (int iy = 0; iy < met->ny; iy++) {
10185
10186 /* Check minimum value... */
10187 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
10188 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
10189
10190 /* Check maximum value... */
10191 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
10192 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
10193 }
10194}
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 10198 of file mptrac.c.

10199 {
10200
10201 /* Set timer... */
10202 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
10203 LOG(2, "Apply periodic boundary conditions...");
10204
10205 /* Check longitudes... */
10206 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
10207 + met->lon[1] - met->lon[0] - 360) < 0.01))
10208 return;
10209
10210 /* Increase longitude counter... */
10211 if ((++met->nx) >= EX)
10212 ERRMSG("Cannot create periodic boundary conditions!");
10213
10214 /* Set longitude... */
10215 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
10216
10217 /* Loop over latitudes and pressure levels... */
10218#pragma omp parallel for default(shared)
10219 for (int iy = 0; iy < met->ny; iy++) {
10220 met->ps[met->nx - 1][iy] = met->ps[0][iy];
10221 met->zs[met->nx - 1][iy] = met->zs[0][iy];
10222 met->ts[met->nx - 1][iy] = met->ts[0][iy];
10223 met->us[met->nx - 1][iy] = met->us[0][iy];
10224 met->vs[met->nx - 1][iy] = met->vs[0][iy];
10225 met->ess[met->nx - 1][iy] = met->ess[0][iy];
10226 met->nss[met->nx - 1][iy] = met->nss[0][iy];
10227 met->shf[met->nx - 1][iy] = met->shf[0][iy];
10228 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
10229 met->sst[met->nx - 1][iy] = met->sst[0][iy];
10230 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
10231 met->cape[met->nx - 1][iy] = met->cape[0][iy];
10232 met->cin[met->nx - 1][iy] = met->cin[0][iy];
10233 for (int ip = 0; ip < met->np; ip++) {
10234 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
10235 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
10236 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
10237 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
10238 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
10239 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
10240 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
10241 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
10242 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
10243 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
10244 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
10245 }
10246 for (int ip = 0; ip < met->npl; ip++) {
10247 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
10248 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
10249 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
10250 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
10251 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
10252 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
10253 }
10254 }
10255}

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

10260 {
10261
10262 /* Set timer... */
10263 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
10264 LOG(2, "Apply fix for polar winds...");
10265
10266 /* Check latitudes... */
10267 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
10268 return;
10269
10270 /* Loop over hemispheres... */
10271 for (int ihem = 0; ihem < 2; ihem++) {
10272
10273 /* Set latitude indices... */
10274 int i89 = 1, i90 = 0, sign = 1;
10275 if (ihem == 1) {
10276 i89 = met->ny - 2;
10277 i90 = met->ny - 1;
10278 }
10279 if (met->lat[i90] < 0)
10280 sign = -1;
10281
10282 /* Look-up table of cosinus and sinus... */
10283 double clon[EX], slon[EX];
10284#pragma omp parallel for default(shared)
10285 for (int ix = 0; ix < met->nx; ix++) {
10286 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
10287 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
10288 }
10289
10290 /* Loop over levels... */
10291#pragma omp parallel for default(shared)
10292 for (int ip = 0; ip < met->np; ip++) {
10293
10294 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
10295 double vel89x = 0, vel89y = 0;
10296 for (int ix = 0; ix < met->nx; ix++) {
10297 vel89x +=
10298 (met->u[ix][i89][ip] * clon[ix] -
10299 met->v[ix][i89][ip] * slon[ix]) / met->nx;
10300 vel89y +=
10301 (met->u[ix][i89][ip] * slon[ix] +
10302 met->v[ix][i89][ip] * clon[ix]) / met->nx;
10303 }
10304
10305 /* Replace 90 degree winds by 89 degree mean... */
10306 for (int ix = 0; ix < met->nx; ix++) {
10307 met->u[ix][i90][ip]
10308 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
10309 met->v[ix][i90][ip]
10310 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
10311 }
10312 }
10313 }
10314}

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

10319 {
10320
10321 double pows[EP];
10322
10323 /* Set timer... */
10324 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
10325 LOG(2, "Calculate potential vorticity...");
10326
10327 /* Set powers... */
10328#pragma omp parallel for default(shared)
10329 for (int ip = 0; ip < met->np; ip++)
10330 pows[ip] = pow(1000. / met->p[ip], 0.286);
10331
10332 /* Loop over grid points... */
10333#pragma omp parallel for default(shared)
10334 for (int ix = 0; ix < met->nx; ix++) {
10335
10336 /* Set indices... */
10337 const int ix0 = MAX(ix - 1, 0);
10338 const int ix1 = MIN(ix + 1, met->nx - 1);
10339
10340 /* Loop over grid points... */
10341 for (int iy = 0; iy < met->ny; iy++) {
10342
10343 /* Set indices... */
10344 const int iy0 = MAX(iy - 1, 0);
10345 const int iy1 = MIN(iy + 1, met->ny - 1);
10346
10347 /* Set auxiliary variables... */
10348 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
10349 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
10350 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
10351 const double c0 = cos(DEG2RAD(met->lat[iy0]));
10352 const double c1 = cos(DEG2RAD(met->lat[iy1]));
10353 const double cr = cos(DEG2RAD(latr));
10354 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
10355
10356 /* Loop over grid points... */
10357 for (int ip = 0; ip < met->np; ip++) {
10358
10359 /* Get gradients in longitude... */
10360 const double dtdx
10361 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
10362 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
10363
10364 /* Get gradients in latitude... */
10365 const double dtdy
10366 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
10367 const double dudy
10368 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
10369
10370 /* Set indices... */
10371 const int ip0 = MAX(ip - 1, 0);
10372 const int ip1 = MIN(ip + 1, met->np - 1);
10373
10374 /* Get gradients in pressure... */
10375 double dtdp, dudp, dvdp;
10376 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
10377 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
10378 if (ip != ip0 && ip != ip1) {
10379 double denom = dp0 * dp1 * (dp0 + dp1);
10380 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
10381 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
10382 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
10383 / denom;
10384 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
10385 - dp1 * dp1 * met->u[ix][iy][ip0]
10386 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
10387 / denom;
10388 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
10389 - dp1 * dp1 * met->v[ix][iy][ip0]
10390 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
10391 / denom;
10392 } else {
10393 const double denom = dp0 + dp1;
10394 dtdp =
10395 (met->t[ix][iy][ip1] * pows[ip1] -
10396 met->t[ix][iy][ip0] * pows[ip0]) / denom;
10397 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
10398 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
10399 }
10400
10401 /* Calculate PV... */
10402 met->pv[ix][iy][ip] = (float)
10403 (1e6 * G0 *
10404 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
10405 }
10406 }
10407 }
10408
10409 /* Fix for polar regions... */
10410#pragma omp parallel for default(shared)
10411 for (int ix = 0; ix < met->nx; ix++)
10412 for (int ip = 0; ip < met->np; ip++) {
10413 met->pv[ix][0][ip]
10414 = met->pv[ix][1][ip]
10415 = met->pv[ix][2][ip];
10416 met->pv[ix][met->ny - 1][ip]
10417 = met->pv[ix][met->ny - 2][ip]
10418 = met->pv[ix][met->ny - 3][ip];
10419 }
10420}
#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 10424 of file mptrac.c.

10425 {
10426
10427 /* Set timer... */
10428 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
10429 LOG(2, "Calculate total column ozone...");
10430
10431 /* Loop over columns... */
10432#pragma omp parallel for default(shared) collapse(2)
10433 for (int ix = 0; ix < met->nx; ix++)
10434 for (int iy = 0; iy < met->ny; iy++) {
10435
10436 /* Integrate... */
10437 double cd = 0;
10438 for (int ip = 1; ip < met->np; ip++)
10439 if (met->p[ip - 1] <= met->ps[ix][iy]) {
10440 const double vmr =
10441 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
10442 const double dp = met->p[ip - 1] - met->p[ip];
10443 cd += vmr * MO3 / MA * dp * 1e2 / G0;
10444 }
10445
10446 /* Convert to Dobson units... */
10447 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
10448 }
10449}

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

10455 {
10456
10457 met_t *help;
10458
10459 /* Check parameters... */
10460 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
10461 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
10462 return;
10463
10464 /* Set timer... */
10465 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
10466 LOG(2, "Downsampling of meteo data...");
10467
10468 /* Allocate... */
10469 ALLOC(help, met_t, 1);
10470
10471 /* Copy data... */
10472 help->nx = met->nx;
10473 help->ny = met->ny;
10474 help->np = met->np;
10475 memcpy(help->lon, met->lon, sizeof(met->lon));
10476 memcpy(help->lat, met->lat, sizeof(met->lat));
10477 memcpy(help->p, met->p, sizeof(met->p));
10478
10479 /* Smoothing... */
10480 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
10481 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
10482 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
10483 help->ps[ix][iy] = 0;
10484 help->zs[ix][iy] = 0;
10485 help->ts[ix][iy] = 0;
10486 help->us[ix][iy] = 0;
10487 help->vs[ix][iy] = 0;
10488 help->ess[ix][iy] = 0;
10489 help->nss[ix][iy] = 0;
10490 help->shf[ix][iy] = 0;
10491 help->lsm[ix][iy] = 0;
10492 help->sst[ix][iy] = 0;
10493 help->pbl[ix][iy] = 0;
10494 help->cape[ix][iy] = 0;
10495 help->cin[ix][iy] = 0;
10496 help->t[ix][iy][ip] = 0;
10497 help->u[ix][iy][ip] = 0;
10498 help->v[ix][iy][ip] = 0;
10499 help->w[ix][iy][ip] = 0;
10500 help->h2o[ix][iy][ip] = 0;
10501 help->o3[ix][iy][ip] = 0;
10502 help->lwc[ix][iy][ip] = 0;
10503 help->rwc[ix][iy][ip] = 0;
10504 help->iwc[ix][iy][ip] = 0;
10505 help->swc[ix][iy][ip] = 0;
10506 help->cc[ix][iy][ip] = 0;
10507 float wsum = 0;
10508 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
10509 ix2++) {
10510 int ix3 = ix2;
10511 if (ix3 < 0)
10512 ix3 += met->nx;
10513 else if (ix3 >= met->nx)
10514 ix3 -= met->nx;
10515
10516 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
10517 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
10518 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
10519 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
10520 const float w =
10521 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
10522 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
10523 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
10524 help->ps[ix][iy] += w * met->ps[ix3][iy2];
10525 help->zs[ix][iy] += w * met->zs[ix3][iy2];
10526 help->ts[ix][iy] += w * met->ts[ix3][iy2];
10527 help->us[ix][iy] += w * met->us[ix3][iy2];
10528 help->vs[ix][iy] += w * met->vs[ix3][iy2];
10529 help->ess[ix][iy] += w * met->ess[ix3][iy2];
10530 help->nss[ix][iy] += w * met->nss[ix3][iy2];
10531 help->shf[ix][iy] += w * met->shf[ix3][iy2];
10532 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
10533 help->sst[ix][iy] += w * met->sst[ix3][iy2];
10534 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
10535 help->cape[ix][iy] += w * met->cape[ix3][iy2];
10536 help->cin[ix][iy] += w * met->cin[ix3][iy2];
10537 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
10538 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
10539 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
10540 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
10541 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
10542 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
10543 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
10544 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
10545 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
10546 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
10547 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
10548 wsum += w;
10549 }
10550 }
10551 help->ps[ix][iy] /= wsum;
10552 help->zs[ix][iy] /= wsum;
10553 help->ts[ix][iy] /= wsum;
10554 help->us[ix][iy] /= wsum;
10555 help->vs[ix][iy] /= wsum;
10556 help->ess[ix][iy] /= wsum;
10557 help->nss[ix][iy] /= wsum;
10558 help->shf[ix][iy] /= wsum;
10559 help->lsm[ix][iy] /= wsum;
10560 help->sst[ix][iy] /= wsum;
10561 help->pbl[ix][iy] /= wsum;
10562 help->cape[ix][iy] /= wsum;
10563 help->cin[ix][iy] /= wsum;
10564 help->t[ix][iy][ip] /= wsum;
10565 help->u[ix][iy][ip] /= wsum;
10566 help->v[ix][iy][ip] /= wsum;
10567 help->w[ix][iy][ip] /= wsum;
10568 help->h2o[ix][iy][ip] /= wsum;
10569 help->o3[ix][iy][ip] /= wsum;
10570 help->lwc[ix][iy][ip] /= wsum;
10571 help->rwc[ix][iy][ip] /= wsum;
10572 help->iwc[ix][iy][ip] /= wsum;
10573 help->swc[ix][iy][ip] /= wsum;
10574 help->cc[ix][iy][ip] /= wsum;
10575 }
10576 }
10577 }
10578
10579 /* Downsampling... */
10580 met->nx = 0;
10581 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
10582 met->lon[met->nx] = help->lon[ix];
10583 met->ny = 0;
10584 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
10585 met->lat[met->ny] = help->lat[iy];
10586 met->ps[met->nx][met->ny] = help->ps[ix][iy];
10587 met->zs[met->nx][met->ny] = help->zs[ix][iy];
10588 met->ts[met->nx][met->ny] = help->ts[ix][iy];
10589 met->us[met->nx][met->ny] = help->us[ix][iy];
10590 met->vs[met->nx][met->ny] = help->vs[ix][iy];
10591 met->ess[met->nx][met->ny] = help->ess[ix][iy];
10592 met->nss[met->nx][met->ny] = help->nss[ix][iy];
10593 met->shf[met->nx][met->ny] = help->shf[ix][iy];
10594 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
10595 met->sst[met->nx][met->ny] = help->sst[ix][iy];
10596 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
10597 met->cape[met->nx][met->ny] = help->cape[ix][iy];
10598 met->cin[met->nx][met->ny] = help->cin[ix][iy];
10599 met->np = 0;
10600 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
10601 met->p[met->np] = help->p[ip];
10602 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
10603 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
10604 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
10605 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
10606 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
10607 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
10608 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
10609 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
10610 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
10611 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
10612 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
10613 met->np++;
10614 }
10615 met->ny++;
10616 }
10617 met->nx++;
10618 }
10619
10620 /* Free... */
10621 free(help);
10622}

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

10629 {
10630
10631 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
10632 th2[200], z[EP], z2[200];
10633
10634 /* Set timer... */
10635 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
10636 LOG(2, "Calculate tropopause...");
10637
10638 /* Get altitude and pressure profiles... */
10639#pragma omp parallel for default(shared)
10640 for (int iz = 0; iz < met->np; iz++)
10641 z[iz] = Z(met->p[iz]);
10642#pragma omp parallel for default(shared)
10643 for (int iz = 0; iz <= 190; iz++) {
10644 z2[iz] = 4.5 + 0.1 * iz;
10645 p2[iz] = P(z2[iz]);
10646 }
10647
10648 /* Do not calculate tropopause... */
10649 if (ctl->met_tropo == 0)
10650#pragma omp parallel for default(shared) collapse(2)
10651 for (int ix = 0; ix < met->nx; ix++)
10652 for (int iy = 0; iy < met->ny; iy++)
10653 met->pt[ix][iy] = NAN;
10654
10655 /* Use tropopause climatology... */
10656 else if (ctl->met_tropo == 1) {
10657#pragma omp parallel for default(shared) collapse(2)
10658 for (int ix = 0; ix < met->nx; ix++)
10659 for (int iy = 0; iy < met->ny; iy++)
10660 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
10661 }
10662
10663 /* Use cold point... */
10664 else if (ctl->met_tropo == 2) {
10665
10666 /* Loop over grid points... */
10667#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10668 for (int ix = 0; ix < met->nx; ix++)
10669 for (int iy = 0; iy < met->ny; iy++) {
10670
10671 /* Interpolate temperature profile... */
10672 for (int iz = 0; iz < met->np; iz++)
10673 t[iz] = met->t[ix][iy][iz];
10674 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
10675
10676 /* Find minimum... */
10677 int iz = (int) gsl_stats_min_index(t2, 1, 171);
10678 if (iz > 0 && iz < 170)
10679 met->pt[ix][iy] = (float) p2[iz];
10680 else
10681 met->pt[ix][iy] = NAN;
10682 }
10683 }
10684
10685 /* Use WMO definition... */
10686 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
10687
10688 /* Loop over grid points... */
10689#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10690 for (int ix = 0; ix < met->nx; ix++)
10691 for (int iy = 0; iy < met->ny; iy++) {
10692
10693 /* Interpolate temperature profile... */
10694 int iz;
10695 for (iz = 0; iz < met->np; iz++)
10696 t[iz] = met->t[ix][iy][iz];
10697 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
10698
10699 /* Find 1st tropopause... */
10700 met->pt[ix][iy] = NAN;
10701 for (iz = 0; iz <= 170; iz++) {
10702 int found = 1;
10703 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10704 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10705 found = 0;
10706 break;
10707 }
10708 if (found) {
10709 if (iz > 0 && iz < 170)
10710 met->pt[ix][iy] = (float) p2[iz];
10711 break;
10712 }
10713 }
10714
10715 /* Find 2nd tropopause... */
10716 if (ctl->met_tropo == 4) {
10717 met->pt[ix][iy] = NAN;
10718 for (; iz <= 170; iz++) {
10719 int found = 1;
10720 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
10721 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
10722 found = 0;
10723 break;
10724 }
10725 if (found)
10726 break;
10727 }
10728 for (; iz <= 170; iz++) {
10729 int found = 1;
10730 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10731 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10732 found = 0;
10733 break;
10734 }
10735 if (found) {
10736 if (iz > 0 && iz < 170)
10737 met->pt[ix][iy] = (float) p2[iz];
10738 break;
10739 }
10740 }
10741 }
10742 }
10743 }
10744
10745 /* Use dynamical tropopause... */
10746 else if (ctl->met_tropo == 5) {
10747
10748 /* Loop over grid points... */
10749#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
10750 for (int ix = 0; ix < met->nx; ix++)
10751 for (int iy = 0; iy < met->ny; iy++) {
10752
10753 /* Interpolate potential vorticity profile... */
10754 for (int iz = 0; iz < met->np; iz++)
10755 pv[iz] = met->pv[ix][iy][iz];
10756 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
10757
10758 /* Interpolate potential temperature profile... */
10759 for (int iz = 0; iz < met->np; iz++)
10760 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
10761 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
10762
10763 /* Find dynamical tropopause... */
10764 met->pt[ix][iy] = NAN;
10765 for (int iz = 0; iz <= 170; iz++)
10766 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
10767 || th2[iz] >= ctl->met_tropo_theta) {
10768 if (iz > 0 && iz < 170)
10769 met->pt[ix][iy] = (float) p2[iz];
10770 break;
10771 }
10772 }
10773 }
10774
10775 else
10776 ERRMSG("Cannot calculate tropopause!");
10777
10778 /* Interpolate temperature, geopotential height, and water vapor... */
10779#pragma omp parallel for default(shared) collapse(2)
10780 for (int ix = 0; ix < met->nx; ix++)
10781 for (int iy = 0; iy < met->ny; iy++) {
10782 double h2ot, tt, zt;
10784 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
10785 met->lat[iy], &tt, ci, cw, 1);
10786 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
10787 met->lat[iy], &zt, ci, cw, 0);
10788 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
10789 met->lat[iy], &h2ot, ci, cw, 0);
10790 met->tt[ix][iy] = (float) tt;
10791 met->zt[ix][iy] = (float) zt;
10792 met->h2ot[ix][iy] = (float) h2ot;
10793 }
10794}
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:11004
#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 10798 of file mptrac.c.

10806 {
10807
10808 /* Write info... */
10809 LOG(1, "Read observation data: %s", filename);
10810
10811 /* Read data... */
10812 if (ctl->obs_type == 0)
10813 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
10814 else if (ctl->obs_type == 1)
10815 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
10816 else
10817 ERRMSG("Set OBS_TYPE to 0 or 1!");
10818
10819 /* Check time... */
10820 for (int i = 1; i < *nobs; i++)
10821 if (rt[i] < rt[i - 1])
10822 ERRMSG("Time must be ascending!");
10823
10824 /* Write info... */
10825 int n = *nobs;
10826 double mini, maxi;
10827 LOG(2, "Number of observations: %d", *nobs);
10828 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
10829 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
10830 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
10831 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
10832 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
10833 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
10834 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
10835 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
10836 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
10837 LOG(2, "Observation range: %g ... %g", mini, maxi);
10838}
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:10842
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:10870
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 10842 of file mptrac.c.

10849 {
10850
10851 /* Open observation data file... */
10852 FILE *in;
10853 if (!(in = fopen(filename, "r")))
10854 ERRMSG("Cannot open file!");
10855
10856 /* Read observations... */
10857 char line[LEN];
10858 while (fgets(line, LEN, in))
10859 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
10860 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
10861 if ((++(*nobs)) >= NOBS)
10862 ERRMSG("Too many observations!");
10863
10864 /* Close observation data file... */
10865 fclose(in);
10866}
#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 10870 of file mptrac.c.

10877 {
10878
10879 int ncid, varid;
10880
10881 /* Open netCDF file... */
10882 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
10883 ERRMSG("Cannot open file!");
10884
10885 /* Read the observations from the NetCDF file... */
10886 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
10887 NC_GET_DOUBLE("time", rt, 1);
10888 NC_GET_DOUBLE("alt", rz, 1);
10889 NC_GET_DOUBLE("lon", rlon, 1);
10890 NC_GET_DOUBLE("lat", rlat, 1);
10891 NC_GET_DOUBLE("obs", robs, 1);
10892
10893 /* Close file... */
10894 NC(nc_close(ncid));
10895}

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

10906 {
10907
10908 FILE *in = NULL;
10909
10910 char fullname1[LEN], fullname2[LEN], rval[LEN];
10911
10912 int contain = 0, i;
10913
10914 /* Open file... */
10915 if (filename[strlen(filename) - 1] != '-')
10916 if (!(in = fopen(filename, "r")))
10917 ERRMSG("Cannot open file!");
10918
10919 /* Set full variable name... */
10920 if (arridx >= 0) {
10921 sprintf(fullname1, "%s[%d]", varname, arridx);
10922 sprintf(fullname2, "%s[*]", varname);
10923 } else {
10924 sprintf(fullname1, "%s", varname);
10925 sprintf(fullname2, "%s", varname);
10926 }
10927
10928 /* Read data... */
10929 if (in != NULL) {
10930 char dummy[LEN], line[LEN], rvarname[LEN];
10931 while (fgets(line, LEN, in)) {
10932 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
10933 if (strcasecmp(rvarname, fullname1) == 0 ||
10934 strcasecmp(rvarname, fullname2) == 0) {
10935 contain = 1;
10936 break;
10937 }
10938 }
10939 }
10940 for (i = 1; i < argc - 1; i++)
10941 if (strcasecmp(argv[i], fullname1) == 0 ||
10942 strcasecmp(argv[i], fullname2) == 0) {
10943 sprintf(rval, "%s", argv[i + 1]);
10944 contain = 1;
10945 break;
10946 }
10947
10948 /* Close file... */
10949 if (in != NULL)
10950 fclose(in);
10951
10952 /* Check for missing variables... */
10953 if (!contain) {
10954 if (strlen(defvalue) > 0)
10955 sprintf(rval, "%s", defvalue);
10956 else
10957 ERRMSG("Missing variable %s!\n", fullname1);
10958 }
10959
10960 /* Write info... */
10961 LOG(1, "%s = %s", fullname1, rval);
10962
10963 /* Return values... */
10964 if (value != NULL)
10965 sprintf(value, "%s", rval);
10966 return atof(rval);
10967}

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

10975 {
10976
10977 /* Convert particle radius from microns to m... */
10978 const double rp_help = rp * 1e-6;
10979
10980 /* Density of dry air [kg / m^3]... */
10981 const double rho = RHO(p, T);
10982
10983 /* Dynamic viscosity of air [kg / (m s)]... */
10984 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
10985
10986 /* Thermal velocity of an air molecule [m / s]... */
10987 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
10988
10989 /* Mean free path of an air molecule [m]... */
10990 const double lambda = 2. * eta / (rho * v);
10991
10992 /* Knudsen number for air (dimensionless)... */
10993 const double K = lambda / rp_help;
10994
10995 /* Cunningham slip-flow correction (dimensionless)... */
10996 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
10997
10998 /* Sedimentation velocity [m / s]... */
10999 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
11000}
#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 11004 of file mptrac.c.

11011 {
11012
11013 /* Cubic spline interpolation... */
11014 if (method == 1) {
11015
11016 /* Allocate... */
11017 gsl_interp_accel *acc = gsl_interp_accel_alloc();
11018 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
11019
11020 /* Interpolate profile... */
11021 gsl_spline_init(s, x, y, (size_t) n);
11022 for (int i = 0; i < n2; i++)
11023 if (x2[i] <= x[0])
11024 y2[i] = y[0];
11025 else if (x2[i] >= x[n - 1])
11026 y2[i] = y[n - 1];
11027 else
11028 y2[i] = gsl_spline_eval(s, x2[i], acc);
11029
11030 /* Free... */
11031 gsl_spline_free(s);
11032 gsl_interp_accel_free(acc);
11033 }
11034
11035 /* Linear interpolation... */
11036 else {
11037 for (int i = 0; i < n2; i++)
11038 if (x2[i] <= x[0])
11039 y2[i] = y[0];
11040 else if (x2[i] >= x[n - 1])
11041 y2[i] = y[n - 1];
11042 else {
11043 const int idx = locate_irr(x, n, x2[i]);
11044 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
11045 }
11046 }
11047}
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 11051 of file mptrac.c.

11053 {
11054
11055 if (n <= 0)
11056 return 0;
11057
11058 float mean = 0, var = 0;
11059
11060 for (int i = 0; i < n; ++i) {
11061 mean += data[i];
11062 var += SQR(data[i]);
11063 }
11064
11065 var = var / (float) n - SQR(mean / (float) n);
11066
11067 return (var > 0 ? sqrtf(var) : 0);
11068}

◆ sza_calc()

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

Calculates the solar zenith angle.

This function calculates the solar zenith angle, which is the angle between the zenith (straight up) and the line connecting the observer to the center of the sun.

Parameters
secSeconds elapsed since 2000-01-01T12:00Z.
lonObserver's longitude in degrees.
latObserver's latitude in degrees.
Returns
The solar zenith angle in radians.

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

Note
This function assumes that the input longitude and latitude are given in degrees.
Author
Lars Hoffmann

Definition at line 11072 of file mptrac.c.

11075 {
11076
11077 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
11078 const double D = sec / 86400 - 0.5;
11079
11080 /* Geocentric apparent ecliptic longitude [rad]... */
11081 const double g = DEG2RAD(357.529 + 0.98560028 * D);
11082 const double q = 280.459 + 0.98564736 * D;
11083 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
11084
11085 /* Mean obliquity of the ecliptic [rad]... */
11086 const double e = DEG2RAD(23.439 - 0.00000036 * D);
11087
11088 /* Declination [rad]... */
11089 const double sindec = sin(e) * sin(L);
11090
11091 /* Right ascension [rad]... */
11092 const double ra = atan2(cos(e) * sin(L), cos(L));
11093
11094 /* Greenwich Mean Sidereal Time [h]... */
11095 const double GMST = 18.697374558 + 24.06570982441908 * D;
11096
11097 /* Local Sidereal Time [h]... */
11098 const double LST = GMST + lon / 15;
11099
11100 /* Hour angle [rad]... */
11101 const double h = LST / 12 * M_PI - ra;
11102
11103 /* Convert latitude... */
11104 const double lat_help = DEG2RAD(lat);
11105
11106 /* Return solar zenith angle [rad]... */
11107 return acos(sin(lat_help) * sindec +
11108 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
11109}

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

11121 {
11122
11123 struct tm t0, t1;
11124
11125 t0.tm_year = 100;
11126 t0.tm_mon = 0;
11127 t0.tm_mday = 1;
11128 t0.tm_hour = 0;
11129 t0.tm_min = 0;
11130 t0.tm_sec = 0;
11131
11132 t1.tm_year = year - 1900;
11133 t1.tm_mon = mon - 1;
11134 t1.tm_mday = day;
11135 t1.tm_hour = hour;
11136 t1.tm_min = min;
11137 t1.tm_sec = sec;
11138
11139 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
11140}

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

11147 {
11148
11149 static char names[NTIMER][100], groups[NTIMER][100];
11150
11151 static double rt_name[NTIMER], rt_group[NTIMER],
11152 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
11153
11154 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
11155
11156 /* Get time... */
11157 t1 = omp_get_wtime();
11158 dt = t1 - t0;
11159
11160 /* Add elapsed time to current timers... */
11161 if (iname >= 0) {
11162 rt_name[iname] += dt;
11163 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
11164 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
11165 ct_name[iname]++;
11166 }
11167 if (igroup >= 0)
11168 rt_group[igroup] += t1 - t0;
11169
11170 /* Report timers... */
11171 if (output) {
11172 for (int i = 0; i < nname; i++)
11173 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
11174 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
11175 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
11176 for (int i = 0; i < ngroup; i++)
11177 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
11178 double total = 0.0;
11179 for (int i = 0; i < nname; i++)
11180 total += rt_name[i];
11181 LOG(1, "TIMER_TOTAL = %.3f s", total);
11182 }
11183
11184 /* Identify IDs of next timer... */
11185 for (iname = 0; iname < nname; iname++)
11186 if (strcasecmp(name, names[iname]) == 0)
11187 break;
11188 for (igroup = 0; igroup < ngroup; igroup++)
11189 if (strcasecmp(group, groups[igroup]) == 0)
11190 break;
11191
11192 /* Check whether this is a new timer... */
11193 if (iname >= nname) {
11194 sprintf(names[iname], "%s", name);
11195 if ((++nname) >= NTIMER)
11196 ERRMSG("Too many timers!");
11197 }
11198
11199 /* Check whether this is a new group... */
11200 if (igroup >= ngroup) {
11201 sprintf(groups[igroup], "%s", group);
11202 if ((++ngroup) >= NTIMER)
11203 ERRMSG("Too many groups!");
11204 }
11205
11206 /* Save starting time... */
11207 t0 = t1;
11208}
#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 11212 of file mptrac.c.

11214 {
11215
11216 char tstr[10];
11217
11218 double t;
11219
11220 /* Get time from filename... */
11221 int len = (int) strlen(filename);
11222 sprintf(tstr, "%.4s", &filename[len - offset]);
11223 int year = atoi(tstr);
11224 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
11225 int mon = atoi(tstr);
11226 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
11227 int day = atoi(tstr);
11228 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
11229 int hour = atoi(tstr);
11230 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
11231 int min = atoi(tstr);
11232
11233 /* Check time... */
11234 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
11235 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
11236 ERRMSG("Cannot read time from filename!");
11237
11238 /* Convert time to Julian seconds... */
11239 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
11240
11241 /* Return time... */
11242 return t;
11243}
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 11247 of file mptrac.c.

11250 {
11251
11252 /* Get tropopause pressure... */
11253 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
11254
11255 /* Get pressure range... */
11256 const double p1 = pt * 0.866877899;
11257 const double p0 = pt / 0.866877899;
11258
11259 /* Get weighting factor... */
11260 if (atm->p[ip] > p0)
11261 return 1;
11262 else if (atm->p[ip] < p1)
11263 return 0;
11264 else
11265 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
11266}
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 11270 of file mptrac.c.

11274 {
11275
11276 FILE *out;
11277
11278 /* Set time interval for output... */
11279 const double t0 = t - 0.5 * ctl->dt_mod;
11280 const double t1 = t + 0.5 * ctl->dt_mod;
11281
11282 /* Check if gnuplot output is requested... */
11283 if (ctl->atm_gpfile[0] != '-') {
11284
11285 /* Create gnuplot pipe... */
11286 if (!(out = popen("gnuplot", "w")))
11287 ERRMSG("Cannot create pipe to gnuplot!");
11288
11289 /* Set plot filename... */
11290 fprintf(out, "set out \"%s.png\"\n", filename);
11291
11292 /* Set time string... */
11293 double r;
11294 int year, mon, day, hour, min, sec;
11295 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11296 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
11297 year, mon, day, hour, min);
11298
11299 /* Dump gnuplot file to pipe... */
11300 FILE *in;
11301 if (!(in = fopen(ctl->atm_gpfile, "r")))
11302 ERRMSG("Cannot open file!");
11303 char line[LEN];
11304 while (fgets(line, LEN, in))
11305 fprintf(out, "%s", line);
11306 fclose(in);
11307 }
11308
11309 else {
11310
11311 /* Create file... */
11312 if (!(out = fopen(filename, "w")))
11313 ERRMSG("Cannot create file!");
11314 }
11315
11316 /* Write header... */
11317 fprintf(out,
11318 "# $1 = time [s]\n"
11319 "# $2 = altitude [km]\n"
11320 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11321 for (int iq = 0; iq < ctl->nq; iq++)
11322 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
11323 ctl->qnt_unit[iq]);
11324 fprintf(out, "\n");
11325
11326 /* Write data... */
11327 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
11328
11329 /* Check time... */
11330 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11331 continue;
11332
11333 /* Write output... */
11334 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
11335 atm->lon[ip], atm->lat[ip]);
11336 for (int iq = 0; iq < ctl->nq; iq++) {
11337 fprintf(out, " ");
11338 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11339 fprintf(out, ctl->qnt_format[iq], NAN);
11340 else
11341 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11342 }
11343 fprintf(out, "\n");
11344 }
11345
11346 /* Close file... */
11347 fclose(out);
11348}
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 11352 of file mptrac.c.

11355 {
11356
11357 FILE *out;
11358
11359 /* Create file... */
11360 if (!(out = fopen(filename, "w")))
11361 ERRMSG("Cannot create file!");
11362
11363 /* Write version of binary data... */
11364 int version = 100;
11365 FWRITE(&version, int,
11366 1,
11367 out);
11368
11369 /* Write data... */
11370 FWRITE(&atm->np, int,
11371 1,
11372 out);
11373 FWRITE(atm->time, double,
11374 (size_t) atm->np,
11375 out);
11376 FWRITE(atm->p, double,
11377 (size_t) atm->np,
11378 out);
11379 FWRITE(atm->lon, double,
11380 (size_t) atm->np,
11381 out);
11382 FWRITE(atm->lat, double,
11383 (size_t) atm->np,
11384 out);
11385 for (int iq = 0; iq < ctl->nq; iq++)
11386 FWRITE(atm->q[iq], double,
11387 (size_t) atm->np,
11388 out);
11389
11390 /* Write final flag... */
11391 int final = 999;
11392 FWRITE(&final, int,
11393 1,
11394 out);
11395
11396 /* Close file... */
11397 fclose(out);
11398}

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

11405 {
11406
11407 int tid, pid, ncid, varid;
11408 size_t start[2], count[2];
11409
11410 /* Create file... */
11411 nc_create(filename, NC_NETCDF4, &ncid);
11412
11413 /* Define dimensions... */
11414 NC(nc_def_dim(ncid, "time", 1, &tid));
11415 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11416
11417 /* Define variables and their attributes... */
11418 int dim_ids[2] = { tid, pid };
11419 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11420 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11421 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11422 ctl->atm_nc_level, 0);
11423 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11424 ctl->atm_nc_level, 0);
11425 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11426 ctl->atm_nc_level, 0);
11427 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11428 for (int iq = 0; iq < ctl->nq; iq++)
11429 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11430 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11431 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11432
11433 /* Define global attributes... */
11434 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11435 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11436
11437 /* End definitions... */
11438 NC(nc_enddef(ncid));
11439
11440 /* Write data... */
11441 NC_PUT_DOUBLE("time", atm->time, 0);
11442 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11443 NC_PUT_DOUBLE("LON", atm->lon, 0);
11444 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11445 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11446 for (int iq = 0; iq < ctl->nq; iq++)
11447 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11448
11449 /* Close file... */
11450 NC(nc_close(ncid));
11451}
#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 11455 of file mptrac.c.

11459 {
11460
11461 /* Global Counter... */
11462 static size_t out_cnt = 0;
11463
11464 double r, r_start, r_stop;
11465 int year, mon, day, hour, min, sec;
11466 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
11467 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
11468 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
11469
11470 int ncid, varid, tid, pid, cid;
11471 int dim_ids[2];
11472
11473 /* time, nparc */
11474 size_t start[2];
11475 size_t count[2];
11476
11477 /* Determine start and stop times of calculation... */
11478 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11479 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
11480 &min_start, &sec_start, &r_start);
11481 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
11482 &min_stop, &sec_stop, &r_stop);
11483
11484 sprintf(filename_out,
11485 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
11486 year_start % 100, mon_start, day_start, hour_start,
11487 year_stop % 100, mon_stop, day_stop, hour_stop);
11488 LOG(1, "Write traj file: %s", filename_out);
11489
11490 /* Define hyperslap for the traj_file... */
11491 start[0] = out_cnt;
11492 start[1] = 0;
11493 count[0] = 1;
11494 count[1] = (size_t) atm->np;
11495
11496 /* Create the file at the first timestep... */
11497 if (out_cnt == 0) {
11498
11499 /* Create file... */
11500 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
11501
11502 /* Define dimensions... */
11503 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
11504 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11505 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
11506 dim_ids[0] = tid;
11507 dim_ids[1] = pid;
11508
11509 /* Define variables and their attributes... */
11510 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11511 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11512 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
11513 ctl->atm_nc_level, 0);
11514 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
11515 ctl->atm_nc_level, 0);
11516 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
11517 ctl->atm_nc_level, 0);
11518 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
11519 ctl->atm_nc_level, 0);
11520 for (int iq = 0; iq < ctl->nq; iq++)
11521 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11522 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11523 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11524
11525 /* Define global attributes... */
11526 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11527 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11528
11529 /* End definitions... */
11530 NC(nc_enddef(ncid));
11531 NC(nc_close(ncid));
11532 }
11533
11534 /* Increment global counter to change hyperslap... */
11535 out_cnt++;
11536
11537 /* Open file... */
11538 NC(nc_open(filename_out, NC_WRITE, &ncid));
11539
11540 /* Write data... */
11541 NC_PUT_DOUBLE("time", atm->time, 1);
11542 NC_PUT_DOUBLE("LAT", atm->lat, 1);
11543 NC_PUT_DOUBLE("LON", atm->lon, 1);
11544 NC_PUT_DOUBLE("PRESS", atm->p, 1);
11545 if (ctl->advect_vert_coord == 1) {
11546 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
11547 } else if (ctl->qnt_zeta >= 0) {
11548 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
11549 }
11550 for (int iq = 0; iq < ctl->nq; iq++)
11551 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
11552
11553 /* Close file... */
11554 NC(nc_close(ncid));
11555
11556 /* At the last time step create the init_fix_YYYYMMDDHH file... */
11557 if ((year == year_stop) && (mon == mon_stop)
11558 && (day == day_stop) && (hour == hour_stop)) {
11559
11560 /* Set filename... */
11561 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
11562 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
11563 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
11564 LOG(1, "Write init file: %s", filename_init);
11565
11566 /* Create file... */
11567 nc_create(filename_init, NC_NETCDF4, &ncid);
11568
11569 /* Define dimensions... */
11570 NC(nc_def_dim(ncid, "time", 1, &tid));
11571 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11572 dim_ids[0] = tid;
11573 dim_ids[1] = pid;
11574
11575 /* Define variables and their attributes... */
11576 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11577 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11578 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11579 ctl->atm_nc_level, 0);
11580 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11581 ctl->atm_nc_level, 0);
11582 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11583 ctl->atm_nc_level, 0);
11584 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11585 for (int iq = 0; iq < ctl->nq; iq++)
11586 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11587 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11588 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11589
11590 /* Define global attributes... */
11591 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11592 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11593
11594 /* End definitions... */
11595 NC(nc_enddef(ncid));
11596
11597 /* Write data... */
11598 NC_PUT_DOUBLE("time", atm->time, 0);
11599 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11600 NC_PUT_DOUBLE("LON", atm->lon, 0);
11601 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11602 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11603 for (int iq = 0; iq < ctl->nq; iq++)
11604 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11605
11606 /* Close file... */
11607 NC(nc_close(ncid));
11608 }
11609}
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 11613 of file mptrac.c.

11616 {
11617
11618 int ncid, obsid, varid;
11619
11620 size_t start[2], count[2];
11621
11622 /* Create file... */
11623 NC(nc_create(filename, NC_NETCDF4, &ncid));
11624
11625 /* Define dimensions... */
11626 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
11627
11628 /* Define variables and their attributes... */
11629 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
11630 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11631 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
11632 ctl->atm_nc_level, 0);
11633 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
11634 ctl->atm_nc_level, 0);
11635 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
11636 ctl->atm_nc_level, 0);
11637 for (int iq = 0; iq < ctl->nq; iq++)
11638 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
11639 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
11640 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11641
11642 /* Define global attributes... */
11643 NC_PUT_ATT_GLOBAL("featureType", "point");
11644
11645 /* End definitions... */
11646 NC(nc_enddef(ncid));
11647
11648 /* Write data... */
11649 NC_PUT_DOUBLE("time", atm->time, 0);
11650 NC_PUT_DOUBLE("press", atm->p, 0);
11651 NC_PUT_DOUBLE("lon", atm->lon, 0);
11652 NC_PUT_DOUBLE("lat", atm->lat, 0);
11653 for (int iq = 0; iq < ctl->nq; iq++)
11654 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11655
11656 /* Close file... */
11657 NC(nc_close(ncid));
11658}

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

11666 {
11667
11668 static FILE *out;
11669
11670 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
11671 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
11672
11673 static int *obscount, nobs, nk;
11674
11675 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
11676
11677 const int ensemble = (ctl->nens > 0);
11678
11679 /* Set timer */
11680 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
11681
11682 /* Check quantities... */
11683 if (ctl->qnt_m < 0)
11684 ERRMSG("Need quantity mass!");
11685 if (ensemble) {
11686 if (ctl->qnt_ens < 0)
11687 ERRMSG("Missing ensemble IDs!");
11688 if (ctl->nens > NENS)
11689 ERRMSG("Too many ensembles!");
11690 }
11691
11692 /* Init... */
11693 if (t == ctl->t_start) {
11694
11695 /* Allocate.. */
11696 ALLOC(area, double,
11697 ctl->csi_ny);
11698 ALLOC(rt, double,
11699 NOBS);
11700 ALLOC(rz, double,
11701 NOBS);
11702 ALLOC(rlon, double,
11703 NOBS);
11704 ALLOC(rlat, double,
11705 NOBS);
11706 ALLOC(robs, double,
11707 NOBS);
11708
11709 /* Read observation data... */
11710 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11711
11712 /* Read kernel data... */
11713 if (ctl->csi_kernel[0] != '-')
11714 read_kernel(ctl->csi_kernel, kz, kw, &nk);
11715
11716 /* Create new file... */
11717 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
11718 if (!(out = fopen(filename, "w")))
11719 ERRMSG("Cannot create file!");
11720
11721 /* Write header... */
11722 fprintf(out,
11723 "# $1 = time [s]\n"
11724 "# $2 = ensemble ID\n"
11725 "# $3 = number of hits (cx)\n"
11726 "# $4 = number of misses (cy)\n"
11727 "# $5 = number of false alarms (cz)\n"
11728 "# $6 = number of observations (cx + cy)\n"
11729 "# $7 = number of forecasts (cx + cz)\n"
11730 "# $8 = bias (%%)\n"
11731 "# $9 = POD (%%)\n"
11732 "# $10 = FAR (%%)\n"
11733 "# $11 = CSI (%%)\n"
11734 "# $12 = hits by random chance\n"
11735 "# $13 = ETS (%%)\n"
11736 "# $14 = Pearson R\n"
11737 "# $15 = Spearman R\n"
11738 "# $16 = mean error [kg/m²]\n"
11739 "# $17 = RMSE [kg/m²]\n"
11740 "# $18 = MAE [kg/m²]\n"
11741 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
11742
11743 /* Set grid box size... */
11744 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
11745 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
11746 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
11747
11748 /* Set horizontal coordinates... */
11749 for (int iy = 0; iy < ctl->csi_ny; iy++) {
11750 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
11751 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
11752 }
11753 }
11754
11755 /* Set time interval... */
11756 const double t0 = t - 0.5 * ctl->dt_mod;
11757 const double t1 = t + 0.5 * ctl->dt_mod;
11758
11759 /* Allocate... */
11760 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
11761 ALLOC(modmean, double,
11762 (ensemble ? ctl->nens : 1) * grid_size);
11763 ALLOC(obsmean, double,
11764 grid_size);
11765 ALLOC(obscount, int,
11766 grid_size);
11767 ALLOC(obsstd, double,
11768 grid_size);
11769
11770 /* Init... */
11771 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
11772 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
11773
11774 /* Loop over observations... */
11775 for (int i = 0; i < nobs; i++) {
11776 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
11777 continue;
11778
11779 /* Calculate indices... */
11780 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
11781 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
11782 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
11783 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11784 || iz >= ctl->csi_nz)
11785 continue;
11786
11787 /* Get mean observation index... */
11788 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11789 obsmean[idx] += robs[i];
11790 obsstd[idx] += SQR(robs[i]);
11791 obscount[idx]++;
11792 }
11793
11794 /* Analyze model data... */
11795 for (int ip = 0; ip < atm->np; ip++) {
11796
11797 /* Check time... */
11798 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11799 continue;
11800
11801 /* Get ensemble ID... */
11802 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
11803 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
11804 ERRMSG("Ensemble ID out of range!");
11805
11806 /* Get indices... */
11807 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
11808 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
11809 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
11810 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11811 || iz >= ctl->csi_nz)
11812 continue;
11813
11814 /* Get total mass in grid cell... */
11815 const int idx =
11816 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11817 modmean[idx] +=
11818 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11819 }
11820 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11821 /* Analyze all grid cells... */
11822 for (int ix = 0; ix < ctl->csi_nx; ix++)
11823 for (int iy = 0; iy < ctl->csi_ny; iy++)
11824 for (int iz = 0; iz < ctl->csi_nz; iz++) {
11825
11826 /* Calculate mean observation index... */
11827 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11828 if (e == 0)
11829 if (obscount[idx]) {
11830 obsmean[idx] /= obscount[idx];
11831 obsstd[idx] =
11832 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
11833 }
11834
11835 /* Calculate model mean per ensemble... */
11836 const int midx = e * grid_size + idx;
11837 if (modmean[midx] > 0)
11838 modmean[midx] /= (1e6 * area[iy]);
11839
11840 /* Check number of observations... */
11841 if (obscount[idx]) {
11842
11843 /* Calculate CSI... */
11844 ct[e]++;
11845 if (obsmean[idx] >= ctl->csi_obsmin
11846 && modmean[midx] >= ctl->csi_modmin)
11847 cx[e]++;
11848 else if (obsmean[idx] >= ctl->csi_obsmin)
11849 cy[e]++;
11850 else if (modmean[midx] >= ctl->csi_modmin)
11851 cz[e]++;
11852
11853 /* Save data for other verification statistics... */
11854 if (obsmean[idx] >= ctl->csi_obsmin
11855 || modmean[midx] >= ctl->csi_modmin) {
11856 x[n[e]] = modmean[midx];
11857 y[n[e]] = obsmean[idx];
11858 if (modmean[midx] >= ctl->csi_modmin)
11859 obsstdn[n[e]] = obsstd[idx];
11860 if ((++n[e]) >= NCSI)
11861 ERRMSG("Too many points for statistics!");
11862 }
11863 }
11864 }
11865 /* Write output... */
11866 if (fmod(t, ctl->csi_dt_out) == 0) {
11867
11868 if (n[e] == 0)
11869 continue;
11870
11871 /* Calculate verification statistics
11872 (https://www.cawcr.gov.au/projects/verification/) ... */
11873 static double work[2 * NCSI], work2[2 * NCSI];
11874 const int n_obs = cx[e] + cy[e];
11875 const int n_for = cx[e] + cz[e];
11876 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
11877 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
11878 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
11879 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
11880 const double csi =
11881 (cx[e] + cy[e] + cz[e] >
11882 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
11883 const double ets =
11884 (cx[e] + cy[e] + cz[e] - cx_rd >
11885 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
11886 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
11887 const double rho_s =
11888 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
11889 for (int i = 0; i < n[e]; i++) {
11890 work[i] = x[i] - y[i];
11891 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
11892 }
11893 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
11894 const double rmse =
11895 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
11896 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
11897 const double loglikelihood =
11898 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
11899
11900 /* Write... */
11901 fprintf(out,
11902 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
11903 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
11904 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
11905 loglikelihood, n[e]);
11906
11907 /* Set counters to zero... */
11908 for (int i = 0; i < n[e]; i++)
11909 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
11910 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
11911 }
11912 }
11913 /* Free... */
11914 free(modmean);
11915 free(obsmean);
11916 free(obscount);
11917 free(obsstd);
11918
11919 /* Finalize... */
11920 if (t == ctl->t_stop) {
11921
11922 /* Close output file... */
11923 fclose(out);
11924
11925 /* Free... */
11926 free(area);
11927 free(rt);
11928 free(rz);
11929 free(rlon);
11930 free(rlat);
11931 free(robs);
11932 }
11933}
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:10798
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:7430
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:2568
#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 11937 of file mptrac.c.

11941 {
11942
11943 static FILE *out;
11944
11945 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
11946 x[3], zm[NENS];
11947
11948 static int n[NENS];
11949
11950 /* Set timer... */
11951 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
11952
11953 /* Check quantities... */
11954 if (ctl->qnt_ens < 0)
11955 ERRMSG("Missing ensemble IDs!");
11956
11957 /* Set time interval... */
11958 const double t0 = t - 0.5 * ctl->dt_mod;
11959 const double t1 = t + 0.5 * ctl->dt_mod;
11960
11961 /* Init... */
11962 for (int i = 0; i < NENS; i++) {
11963 for (int iq = 0; iq < ctl->nq; iq++)
11964 qm[iq][i] = qs[iq][i] = 0;
11965 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
11966 n[i] = 0;
11967 }
11968
11969 /* Loop over air parcels... */
11970 for (int ip = 0; ip < atm->np; ip++) {
11971
11972 /* Check time... */
11973 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11974 continue;
11975
11976 /* Check ensemble ID... */
11977 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
11978 ERRMSG("Ensemble ID is out of range!");
11979
11980 /* Get means... */
11981 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
11982 for (int iq = 0; iq < ctl->nq; iq++) {
11983 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
11984 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
11985 }
11986 xm[ctl->qnt_ens][0] += x[0];
11987 xm[ctl->qnt_ens][1] += x[1];
11988 xm[ctl->qnt_ens][2] += x[2];
11989 zm[ctl->qnt_ens] += Z(atm->p[ip]);
11990 n[ctl->qnt_ens]++;
11991 }
11992
11993 /* Create file... */
11994 LOG(1, "Write ensemble data: %s", filename);
11995 if (!(out = fopen(filename, "w")))
11996 ERRMSG("Cannot create file!");
11997
11998 /* Write header... */
11999 fprintf(out,
12000 "# $1 = time [s]\n"
12001 "# $2 = altitude [km]\n"
12002 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12003 for (int iq = 0; iq < ctl->nq; iq++)
12004 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
12005 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12006 for (int iq = 0; iq < ctl->nq; iq++)
12007 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
12008 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12009 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
12010
12011 /* Write data... */
12012 for (int i = 0; i < NENS; i++)
12013 if (n[i] > 0) {
12014 cart2geo(xm[i], &dummy, &lon, &lat);
12015 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
12016 for (int iq = 0; iq < ctl->nq; iq++) {
12017 fprintf(out, " ");
12018 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
12019 }
12020 for (int iq = 0; iq < ctl->nq; iq++) {
12021 fprintf(out, " ");
12022 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
12023 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
12024 }
12025 fprintf(out, " %d\n", n[i]);
12026 }
12027
12028 /* Close file... */
12029 fclose(out);
12030}
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 12034 of file mptrac.c.

12040 {
12041
12042 static double kz[EP], kw[EP];
12043
12044 static int nk;
12045
12046 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
12047
12048 int *ixs, *iys, *izs, *np;
12049
12050 /* Set timer... */
12051 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
12052
12053 /* Write info... */
12054 LOG(1, "Write grid data: %s", filename);
12055
12056 /* Init... */
12057 if (t == ctl->t_start) {
12058
12059 /* Read kernel data... */
12060 if (ctl->grid_kernel[0] != '-')
12061 read_kernel(ctl->grid_kernel, kz, kw, &nk);
12062 }
12063
12064 /* Allocate... */
12065 ALLOC(cd, double,
12066 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12067 for (int iq = 0; iq < ctl->nq; iq++) {
12068 ALLOC(mean[iq], double,
12069 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12070 ALLOC(sigma[iq], double,
12071 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12072 }
12073 ALLOC(vmr_impl, double,
12074 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12075 ALLOC(z, double,
12076 ctl->grid_nz);
12077 ALLOC(lon, double,
12078 ctl->grid_nx);
12079 ALLOC(lat, double,
12080 ctl->grid_ny);
12081 ALLOC(area, double,
12082 ctl->grid_ny);
12083 ALLOC(press, double,
12084 ctl->grid_nz);
12085 ALLOC(np, int,
12086 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12087 ALLOC(ixs, int,
12088 atm->np);
12089 ALLOC(iys, int,
12090 atm->np);
12091 ALLOC(izs, int,
12092 atm->np);
12093
12094 /* Set grid box size... */
12095 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
12096 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
12097 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
12098
12099 /* Set vertical coordinates... */
12100#pragma omp parallel for default(shared)
12101 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12102 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
12103 press[iz] = P(z[iz]);
12104 }
12105
12106 /* Set horizontal coordinates... */
12107 for (int ix = 0; ix < ctl->grid_nx; ix++)
12108 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
12109#pragma omp parallel for default(shared)
12110 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12111 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
12112 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
12113 }
12114
12115 /* Set time interval for output... */
12116 const double t0 = t - 0.5 * ctl->dt_mod;
12117 const double t1 = t + 0.5 * ctl->dt_mod;
12118
12119 /* Get grid box indices... */
12120#pragma omp parallel for default(shared)
12121 for (int ip = 0; ip < atm->np; ip++) {
12122 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
12123 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
12124 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
12125 if (atm->time[ip] < t0 || atm->time[ip] > t1
12126 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
12127 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
12128 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
12129 izs[ip] = -1;
12130 }
12131
12132 /* Average data... */
12133 for (int ip = 0; ip < atm->np; ip++)
12134 if (izs[ip] >= 0) {
12135 const int idx =
12136 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
12137 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
12138 np[idx]++;
12139 for (int iq = 0; iq < ctl->nq; iq++) {
12140 mean[iq][idx] += kernel * atm->q[iq][ip];
12141 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
12142 }
12143 }
12144
12145 /* Calculate column density and volume mixing ratio... */
12146#pragma omp parallel for default(shared)
12147 for (int ix = 0; ix < ctl->grid_nx; ix++)
12148 for (int iy = 0; iy < ctl->grid_ny; iy++)
12149 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12150
12151 /* Get grid index... */
12152 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12153
12154 /* Calculate column density... */
12155 cd[idx] = NAN;
12156 if (ctl->qnt_m >= 0)
12157 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
12158
12159 /* Calculate volume mixing ratio (implicit)... */
12160 vmr_impl[idx] = NAN;
12161 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
12162 && met1 != NULL) {
12163 vmr_impl[idx] = 0;
12164 if (mean[ctl->qnt_m][idx] > 0) {
12165
12166 /* Get temperature... */
12167 double temp;
12169 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
12170 lon[ix], lat[iy], &temp, ci, cw, 1);
12171
12172 /* Calculate volume mixing ratio... */
12173 vmr_impl[idx] =
12174 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
12175 }
12176 }
12177
12178 /* Calculate mean... */
12179 if (np[idx] > 0)
12180 for (int iq = 0; iq < ctl->nq; iq++) {
12181 mean[iq][idx] /= np[idx];
12182 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
12183 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
12184 } else
12185 for (int iq = 0; iq < ctl->nq; iq++) {
12186 mean[iq][idx] = NAN;
12187 sigma[iq][idx] = NAN;
12188 }
12189 }
12190
12191 /* Write ASCII data... */
12192 if (ctl->grid_type == 0)
12193 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
12194 t, z, lon, lat, area, dz, np);
12195
12196 /* Write netCDF data... */
12197 else if (ctl->grid_type == 1)
12198 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
12199 t, z, lon, lat, area, dz, np);
12200
12201 /* Error message... */
12202 else
12203 ERRMSG("Grid data format GRID_TYPE unknown!");
12204
12205 /* Free... */
12206 free(cd);
12207 for (int iq = 0; iq < ctl->nq; iq++) {
12208 free(mean[iq]);
12209 free(sigma[iq]);
12210 }
12211 free(vmr_impl);
12212 free(z);
12213 free(lon);
12214 free(lat);
12215 free(area);
12216 free(press);
12217 free(np);
12218 free(ixs);
12219 free(iys);
12220 free(izs);
12221}
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:12225
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:12329
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 12225 of file mptrac.c.

12238 {
12239
12240 FILE *out;
12241
12242 /* Check if gnuplot output is requested... */
12243 if (ctl->grid_gpfile[0] != '-') {
12244
12245 /* Create gnuplot pipe... */
12246 if (!(out = popen("gnuplot", "w")))
12247 ERRMSG("Cannot create pipe to gnuplot!");
12248
12249 /* Set plot filename... */
12250 fprintf(out, "set out \"%s.png\"\n", filename);
12251
12252 /* Set time string... */
12253 double r;
12254 int year, mon, day, hour, min, sec;
12255 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12256 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12257 year, mon, day, hour, min);
12258
12259 /* Dump gnuplot file to pipe... */
12260 FILE *in;
12261 char line[LEN];
12262 if (!(in = fopen(ctl->grid_gpfile, "r")))
12263 ERRMSG("Cannot open file!");
12264 while (fgets(line, LEN, in))
12265 fprintf(out, "%s", line);
12266 fclose(in);
12267 }
12268
12269 else {
12270
12271 /* Create file... */
12272 if (!(out = fopen(filename, "w")))
12273 ERRMSG("Cannot create file!");
12274 }
12275
12276 /* Write header... */
12277 fprintf(out,
12278 "# $1 = time [s]\n"
12279 "# $2 = altitude [km]\n"
12280 "# $3 = longitude [deg]\n"
12281 "# $4 = latitude [deg]\n"
12282 "# $5 = surface area [km^2]\n"
12283 "# $6 = layer depth [km]\n"
12284 "# $7 = column density (implicit) [kg/m^2]\n"
12285 "# $8 = volume mixing ratio (implicit) [ppv]\n"
12286 "# $9 = number of particles [1]\n");
12287 for (int iq = 0; iq < ctl->nq; iq++)
12288 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
12289 ctl->qnt_unit[iq]);
12290 if (ctl->grid_stddev)
12291 for (int iq = 0; iq < ctl->nq; iq++)
12292 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
12293 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12294 fprintf(out, "\n");
12295
12296 /* Write data... */
12297 for (int ix = 0; ix < ctl->grid_nx; ix++) {
12298 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
12299 fprintf(out, "\n");
12300 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12301 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
12302 fprintf(out, "\n");
12303 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12304 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12305 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
12306 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
12307 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
12308 for (int iq = 0; iq < ctl->nq; iq++) {
12309 fprintf(out, " ");
12310 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
12311 }
12312 if (ctl->grid_stddev)
12313 for (int iq = 0; iq < ctl->nq; iq++) {
12314 fprintf(out, " ");
12315 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
12316 }
12317 fprintf(out, "\n");
12318 }
12319 }
12320 }
12321 }
12322
12323 /* Close file... */
12324 fclose(out);
12325}
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 12329 of file mptrac.c.

12342 {
12343
12344 char longname[2 * LEN], varname[2 * LEN];
12345
12346 double *help;
12347
12348 int *help2, ncid, dimid[10], varid;
12349
12350 size_t start[2], count[2];
12351
12352 /* Allocate... */
12353 ALLOC(help, double,
12354 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12355 ALLOC(help2, int,
12356 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12357
12358 /* Create file... */
12359 NC(nc_create(filename, NC_NETCDF4, &ncid));
12360
12361 /* Define dimensions... */
12362 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
12363 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
12364 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
12365 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
12366 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
12367
12368 /* Define variables and their attributes... */
12369 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
12370 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12371 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
12372 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
12373 0);
12374 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
12375 0);
12376 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
12377 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
12378
12379 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
12380 ctl->grid_nc_level, 0);
12381 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
12382 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
12383 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
12384 for (int iq = 0; iq < ctl->nq; iq++) {
12385 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12386 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
12387 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12388 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12389 if (ctl->grid_stddev) {
12390 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12391 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
12392 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12393 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12394 }
12395 }
12396 /* End definitions... */
12397 NC(nc_enddef(ncid));
12398
12399 /* Write data... */
12400 NC_PUT_DOUBLE("time", &t, 0);
12401 NC_PUT_DOUBLE("lon", lon, 0);
12402 NC_PUT_DOUBLE("lat", lat, 0);
12403 NC_PUT_DOUBLE("z", z, 0);
12404 NC_PUT_DOUBLE("area", area, 0);
12405 NC_PUT_DOUBLE("dz", &dz, 0);
12406
12407 for (int ix = 0; ix < ctl->grid_nx; ix++)
12408 for (int iy = 0; iy < ctl->grid_ny; iy++)
12409 for (int iz = 0; iz < ctl->grid_nz; iz++)
12410 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12411 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12412 NC_PUT_DOUBLE("cd", help, 0);
12413
12414 for (int ix = 0; ix < ctl->grid_nx; ix++)
12415 for (int iy = 0; iy < ctl->grid_ny; iy++)
12416 for (int iz = 0; iz < ctl->grid_nz; iz++)
12417 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12418 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12419 NC_PUT_DOUBLE("vmr_impl", help, 0);
12420
12421 for (int ix = 0; ix < ctl->grid_nx; ix++)
12422 for (int iy = 0; iy < ctl->grid_ny; iy++)
12423 for (int iz = 0; iz < ctl->grid_nz; iz++)
12424 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12425 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12426 NC_PUT_INT("np", help2, 0);
12427
12428 for (int iq = 0; iq < ctl->nq; iq++) {
12429 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12430 for (int ix = 0; ix < ctl->grid_nx; ix++)
12431 for (int iy = 0; iy < ctl->grid_ny; iy++)
12432 for (int iz = 0; iz < ctl->grid_nz; iz++)
12433 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12434 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12435 NC_PUT_DOUBLE(varname, help, 0);
12436 }
12437
12438 if (ctl->grid_stddev)
12439 for (int iq = 0; iq < ctl->nq; iq++) {
12440 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12441 for (int ix = 0; ix < ctl->grid_nx; ix++)
12442 for (int iy = 0; iy < ctl->grid_ny; iy++)
12443 for (int iz = 0; iz < ctl->grid_nz; iz++)
12444 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12445 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12446 NC_PUT_DOUBLE(varname, help, 0);
12447 }
12448
12449 /* Close file... */
12450 NC(nc_close(ncid));
12451
12452 /* Free... */
12453 free(help);
12454 free(help2);
12455}
#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 12459 of file mptrac.c.

12462 {
12463
12464 /* Create file... */
12465 FILE *out;
12466 if (!(out = fopen(filename, "w")))
12467 ERRMSG("Cannot create file!");
12468
12469 /* Write type of binary data... */
12470 FWRITE(&ctl->met_type, int,
12471 1,
12472 out);
12473
12474 /* Write version of binary data... */
12475 int version = 103;
12476 FWRITE(&version, int,
12477 1,
12478 out);
12479
12480 /* Write grid data... */
12481 FWRITE(&met->time, double,
12482 1,
12483 out);
12484 FWRITE(&met->nx, int,
12485 1,
12486 out);
12487 FWRITE(&met->ny, int,
12488 1,
12489 out);
12490 FWRITE(&met->np, int,
12491 1,
12492 out);
12493 FWRITE(met->lon, double,
12494 (size_t) met->nx,
12495 out);
12496 FWRITE(met->lat, double,
12497 (size_t) met->ny,
12498 out);
12499 FWRITE(met->p, double,
12500 (size_t) met->np,
12501 out);
12502
12503 /* Write surface data... */
12504 write_met_bin_2d(out, met, met->ps, "PS");
12505 write_met_bin_2d(out, met, met->ts, "TS");
12506 write_met_bin_2d(out, met, met->zs, "ZS");
12507 write_met_bin_2d(out, met, met->us, "US");
12508 write_met_bin_2d(out, met, met->vs, "VS");
12509 write_met_bin_2d(out, met, met->ess, "ESS");
12510 write_met_bin_2d(out, met, met->nss, "NSS");
12511 write_met_bin_2d(out, met, met->shf, "SHF");
12512 write_met_bin_2d(out, met, met->lsm, "LSM");
12513 write_met_bin_2d(out, met, met->sst, "SST");
12514 write_met_bin_2d(out, met, met->pbl, "PBL");
12515 write_met_bin_2d(out, met, met->pt, "PT");
12516 write_met_bin_2d(out, met, met->tt, "TT");
12517 write_met_bin_2d(out, met, met->zt, "ZT");
12518 write_met_bin_2d(out, met, met->h2ot, "H2OT");
12519 write_met_bin_2d(out, met, met->pct, "PCT");
12520 write_met_bin_2d(out, met, met->pcb, "PCB");
12521 write_met_bin_2d(out, met, met->cl, "CL");
12522 write_met_bin_2d(out, met, met->plcl, "PLCL");
12523 write_met_bin_2d(out, met, met->plfc, "PLFC");
12524 write_met_bin_2d(out, met, met->pel, "PEL");
12525 write_met_bin_2d(out, met, met->cape, "CAPE");
12526 write_met_bin_2d(out, met, met->cin, "CIN");
12527 write_met_bin_2d(out, met, met->o3c, "O3C");
12528
12529 /* Write level data... */
12530 write_met_bin_3d(out, ctl, met, met->z, "Z",
12531 ctl->met_comp_prec[0], ctl->met_comp_tol[0]);
12532 write_met_bin_3d(out, ctl, met, met->t, "T",
12533 ctl->met_comp_prec[1], ctl->met_comp_tol[1]);
12534 write_met_bin_3d(out, ctl, met, met->u, "U",
12535 ctl->met_comp_prec[2], ctl->met_comp_tol[2]);
12536 write_met_bin_3d(out, ctl, met, met->v, "V",
12537 ctl->met_comp_prec[3], ctl->met_comp_tol[3]);
12538 write_met_bin_3d(out, ctl, met, met->w, "W",
12539 ctl->met_comp_prec[4], ctl->met_comp_tol[4]);
12540 write_met_bin_3d(out, ctl, met, met->pv, "PV",
12541 ctl->met_comp_prec[5], ctl->met_comp_tol[5]);
12542 write_met_bin_3d(out, ctl, met, met->h2o, "H2O",
12543 ctl->met_comp_prec[6], ctl->met_comp_tol[6]);
12544 write_met_bin_3d(out, ctl, met, met->o3, "O3",
12545 ctl->met_comp_prec[7], ctl->met_comp_tol[7]);
12546 write_met_bin_3d(out, ctl, met, met->lwc, "LWC",
12547 ctl->met_comp_prec[8], ctl->met_comp_tol[8]);
12548 write_met_bin_3d(out, ctl, met, met->rwc, "RWC",
12549 ctl->met_comp_prec[9], ctl->met_comp_tol[9]);
12550 write_met_bin_3d(out, ctl, met, met->iwc, "IWC",
12551 ctl->met_comp_prec[10], ctl->met_comp_tol[10]);
12552 write_met_bin_3d(out, ctl, met, met->swc, "SWC",
12553 ctl->met_comp_prec[11], ctl->met_comp_tol[11]);
12554 write_met_bin_3d(out, ctl, met, met->cc, "CC",
12555 ctl->met_comp_prec[12], ctl->met_comp_tol[12]);
12556 if (METVAR != 13)
12557 ERRMSG("Number of meteo variables doesn't match!");
12558
12559 /* Write final flag... */
12560 int final = 999;
12561 FWRITE(&final, int,
12562 1,
12563 out);
12564
12565 /* Close file... */
12566 fclose(out);
12567}
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:12600
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:12571
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 12571 of file mptrac.c.

12575 {
12576
12577 float *help;
12578
12579 /* Allocate... */
12580 ALLOC(help, float,
12581 EX * EY);
12582
12583 /* Copy data... */
12584 for (int ix = 0; ix < met->nx; ix++)
12585 for (int iy = 0; iy < met->ny; iy++)
12586 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
12587
12588 /* Write uncompressed data... */
12589 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
12590 FWRITE(help, float,
12591 (size_t) (met->nx * met->ny),
12592 out);
12593
12594 /* Free... */
12595 free(help);
12596}

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

12607 {
12608
12609 float *help;
12610
12611 /* Allocate... */
12612 ALLOC(help, float,
12613 EX * EY * EP);
12614
12615 /* Copy data... */
12616#pragma omp parallel for default(shared) collapse(2)
12617 for (int ix = 0; ix < met->nx; ix++)
12618 for (int iy = 0; iy < met->ny; iy++)
12619 for (int ip = 0; ip < met->np; ip++)
12620 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
12621
12622 /* Write uncompressed data... */
12623 if (ctl->met_type == 1) {
12624 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
12625 FWRITE(help, float,
12626 (size_t) (met->nx * met->ny * met->np),
12627 out);
12628 }
12629
12630 /* Write packed data... */
12631 else if (ctl->met_type == 2)
12632 compress_pck(varname, help, (size_t) (met->ny * met->nx),
12633 (size_t) met->np, 0, out);
12634
12635 /* Write ZFP data... */
12636#ifdef ZFP
12637 else if (ctl->met_type == 3) {
12638 FWRITE(&precision, int,
12639 1,
12640 out);
12641 FWRITE(&tolerance, double,
12642 1,
12643 out);
12644 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
12645 tolerance, 0, out);
12646 }
12647#endif
12648
12649 /* Write zstd data... */
12650#ifdef ZSTD
12651 else if (ctl->met_type == 4)
12652 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
12653 ctl->met_zstd_level, out);
12654#endif
12655
12656 /* Write cmultiscale data... */
12657#ifdef CMS
12658 else if (ctl->met_type == 5) {
12659 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
12660 (size_t) met->np, 0, out);
12661 }
12662#endif
12663
12664 /* Write SZ3 data... */
12665#ifdef SZ3
12666 else if (ctl->met_type == 7) {
12667 FWRITE(&precision, int,
12668 1,
12669 out);
12670 FWRITE(&tolerance, double,
12671 1,
12672 out);
12673 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
12674 tolerance, 0, out);
12675 }
12676#endif
12677
12678 /* Unknown method... */
12679 else {
12680 ERRMSG("MET_TYPE not supported!");
12681 LOG(3, "%d %g", precision, tolerance);
12682 }
12683
12684 /* Free... */
12685 free(help);
12686}
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 12690 of file mptrac.c.

12693 {
12694
12695 /* Create file... */
12696 int ncid, varid;
12697 size_t start[4], count[4];
12698 nc_create(filename, NC_NETCDF4, &ncid);
12699
12700 /* Define dimensions... */
12701 int tid, lonid, latid, levid;
12702 NC(nc_def_dim(ncid, "time", 1, &tid));
12703 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
12704 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
12705 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
12706
12707 /* Define grid... */
12708 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
12709 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12710 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
12711 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
12712 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
12713
12714 /* Define surface variables... */
12715 int dimid2[2] = { latid, lonid };
12716 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
12717 ctl->met_nc_level, 0);
12718 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
12719 ctl->met_nc_level, 0);
12720 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
12721 ctl->met_nc_level, 0);
12722 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
12723 "m s**-1", ctl->met_nc_level, 0);
12724 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
12725 "m s**-1", ctl->met_nc_level, 0);
12726 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
12727 "Instantaneous eastward turbulent surface stress", "N m**-2",
12728 ctl->met_nc_level, 0);
12729 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
12730 "Instantaneous northward turbulent surface stress", "N m**-2",
12731 ctl->met_nc_level, 0);
12732 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
12733 "Instantaneous surface sensible heat flux", "W m**-1",
12734 ctl->met_nc_level, 0);
12735 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
12736 ctl->met_nc_level, 0);
12737 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
12738 ctl->met_nc_level, 0);
12739 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
12740 ctl->met_nc_level, 0);
12741 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
12742 ctl->met_nc_level, 0);
12743 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
12744 ctl->met_nc_level, 0);
12745 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
12746 ctl->met_nc_level, 0);
12747 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
12748 ctl->met_nc_level, 0);
12749 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
12750 ctl->met_nc_level, 0);
12751 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
12752 ctl->met_nc_level, 0);
12753 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
12754 "kg m**2", ctl->met_nc_level, 0);
12755 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
12756 "Pressure at lifted condensation level (LCL)", "Pa",
12757 ctl->met_nc_level, 0);
12758 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
12759 "Pressure at level of free convection (LFC)", "Pa",
12760 ctl->met_nc_level, 0);
12761 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
12762 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
12763 0);
12764 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
12765 "Convective available potential energy", "J kg**-1",
12766 ctl->met_nc_level, 0);
12767 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
12768 "J kg**-1", ctl->met_nc_level, 0);
12769 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
12770 ctl->met_nc_level, 0);
12771
12772 /* Define level data... */
12773 int dimid3[3] = { levid, latid, lonid };
12774 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
12775 ctl->met_nc_level, ctl->met_nc_quant);
12776 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
12777 ctl->met_nc_level, ctl->met_nc_quant);
12778 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
12779 ctl->met_nc_level, ctl->met_nc_quant);
12780 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
12781 ctl->met_nc_level, ctl->met_nc_quant);
12782 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
12783 ctl->met_nc_level, ctl->met_nc_quant);
12784 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
12785 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12786 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
12787 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12788 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
12789 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12790 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
12791 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12792 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
12793 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12794 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
12795 ctl->met_nc_level, ctl->met_nc_quant);
12796
12797 /* End definitions... */
12798 NC(nc_enddef(ncid));
12799
12800 /* Write grid data... */
12801 NC_PUT_DOUBLE("time", &met->time, 0);
12802 NC_PUT_DOUBLE("lon", met->lon, 0);
12803 NC_PUT_DOUBLE("lat", met->lat, 0);
12804 double phelp[EP];
12805 for (int ip = 0; ip < met->np; ip++)
12806 phelp[ip] = 100. * met->p[ip];
12807 NC_PUT_DOUBLE("lev", phelp, 0);
12808
12809 /* Write surface data... */
12810 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
12811 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
12812 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
12813 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
12814 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
12815 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
12816 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
12817 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
12818 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
12819 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
12820 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
12821 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
12822 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
12823 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
12824 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
12825 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
12826 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
12827 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
12828 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
12829 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
12830 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
12831 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
12832 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
12833 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
12834
12835 /* Write level data... */
12836 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
12837 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
12838 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
12839 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
12840 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
12841 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
12842 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
12843 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
12844 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
12845 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
12846 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
12847
12848 /* Close file... */
12849 NC(nc_close(ncid));
12850}
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:12854
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:12883
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.
Returns
void This function does not return any value.
Author
Lars Hoffmann

Definition at line 12854 of file mptrac.c.

12859 {
12860
12861 int varid;
12862 size_t start[4], count[4];
12863
12864 /* Allocate... */
12865 float *help;
12866 ALLOC(help, float,
12867 EX * EY);
12868
12869 /* Copy data... */
12870 for (int ix = 0; ix < met->nx; ix++)
12871 for (int iy = 0; iy < met->ny; iy++)
12872 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
12873
12874 /* Write data... */
12875 NC_PUT_FLOAT(varname, help, 0);
12876
12877 /* Free... */
12878 free(help);
12879}
#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.
Returns
void This function does not return any value.
Author
Lars Hoffmann

Definition at line 12883 of file mptrac.c.

12888 {
12889
12890 int varid;
12891 size_t start[4], count[4];
12892
12893 /* Allocate... */
12894 float *help;
12895 ALLOC(help, float,
12896 EX * EY * EP);
12897
12898 /* Copy data... */
12899 for (int ix = 0; ix < met->nx; ix++)
12900 for (int iy = 0; iy < met->ny; iy++)
12901 for (int ip = 0; ip < met->np; ip++)
12902 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
12903
12904 /* Write data... */
12905 NC_PUT_FLOAT(varname, help, 0);
12906
12907 /* Free... */
12908 free(help);
12909}

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

12919 {
12920
12921 static FILE *out;
12922
12923 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
12924 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
12925
12926 static int nobs, *obscount, ip, okay;
12927
12928 /* Set timer... */
12929 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
12930
12931 /* Init... */
12932 if (t == ctl->t_start) {
12933
12934 /* Check quantity index for mass... */
12935 if (ctl->qnt_m < 0)
12936 ERRMSG("Need quantity mass!");
12937
12938 /* Check molar mass... */
12939 if (ctl->molmass <= 0)
12940 ERRMSG("Specify molar mass!");
12941
12942 /* Allocate... */
12943 ALLOC(lon, double,
12944 ctl->prof_nx);
12945 ALLOC(lat, double,
12946 ctl->prof_ny);
12947 ALLOC(area, double,
12948 ctl->prof_ny);
12949 ALLOC(z, double,
12950 ctl->prof_nz);
12951 ALLOC(press, double,
12952 ctl->prof_nz);
12953 ALLOC(rt, double,
12954 NOBS);
12955 ALLOC(rz, double,
12956 NOBS);
12957 ALLOC(rlon, double,
12958 NOBS);
12959 ALLOC(rlat, double,
12960 NOBS);
12961 ALLOC(robs, double,
12962 NOBS);
12963
12964 /* Read observation data... */
12965 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12966
12967 /* Create new output file... */
12968 LOG(1, "Write profile data: %s", filename);
12969 if (!(out = fopen(filename, "w")))
12970 ERRMSG("Cannot create file!");
12971
12972 /* Write header... */
12973 fprintf(out,
12974 "# $1 = time [s]\n"
12975 "# $2 = altitude [km]\n"
12976 "# $3 = longitude [deg]\n"
12977 "# $4 = latitude [deg]\n"
12978 "# $5 = pressure [hPa]\n"
12979 "# $6 = temperature [K]\n"
12980 "# $7 = volume mixing ratio [ppv]\n"
12981 "# $8 = H2O volume mixing ratio [ppv]\n"
12982 "# $9 = O3 volume mixing ratio [ppv]\n"
12983 "# $10 = observed BT index [K]\n"
12984 "# $11 = number of observations\n");
12985
12986 /* Set grid box size... */
12987 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
12988 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
12989 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
12990
12991 /* Set vertical coordinates... */
12992 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12993 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
12994 press[iz] = P(z[iz]);
12995 }
12996
12997 /* Set horizontal coordinates... */
12998 for (int ix = 0; ix < ctl->prof_nx; ix++)
12999 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
13000 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13001 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
13002 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13003 }
13004 }
13005
13006 /* Set time interval... */
13007 const double t0 = t - 0.5 * ctl->dt_mod;
13008 const double t1 = t + 0.5 * ctl->dt_mod;
13009
13010 /* Allocate... */
13011 ALLOC(mass, double,
13012 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
13013 ALLOC(obsmean, double,
13014 ctl->prof_nx * ctl->prof_ny);
13015 ALLOC(obscount, int,
13016 ctl->prof_nx * ctl->prof_ny);
13017
13018 /* Loop over observations... */
13019 for (int i = 0; i < nobs; i++) {
13020
13021 /* Check time... */
13022 if (rt[i] < t0)
13023 continue;
13024 else if (rt[i] >= t1)
13025 break;
13026
13027 /* Check observation data... */
13028 if (!isfinite(robs[i]))
13029 continue;
13030
13031 /* Calculate indices... */
13032 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
13033 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
13034
13035 /* Check indices... */
13036 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
13037 continue;
13038
13039 /* Get mean observation index... */
13040 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
13041 obsmean[idx] += robs[i];
13042 obscount[idx]++;
13043 }
13044
13045 /* Analyze model data... */
13046 for (ip = 0; ip < atm->np; ip++) {
13047
13048 /* Check time... */
13049 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13050 continue;
13051
13052 /* Get indices... */
13053 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
13054 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
13055 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
13056
13057 /* Check indices... */
13058 if (ix < 0 || ix >= ctl->prof_nx ||
13059 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
13060 continue;
13061
13062 /* Get total mass in grid cell... */
13063 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13064 mass[idx] += atm->q[ctl->qnt_m][ip];
13065 }
13066
13067 /* Extract profiles... */
13068 for (int ix = 0; ix < ctl->prof_nx; ix++)
13069 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13070 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
13071 if (obscount[idx2] > 0) {
13072
13073 /* Check profile... */
13074 okay = 0;
13075 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13076 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13077 if (mass[idx3] > 0) {
13078 okay = 1;
13079 break;
13080 }
13081 }
13082 if (!okay)
13083 continue;
13084
13085 /* Write output... */
13086 fprintf(out, "\n");
13087
13088 /* Loop over altitudes... */
13089 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13090
13091 /* Get temperature, water vapor, and ozone... */
13093 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
13094 lon[ix], lat[iy], &temp, ci, cw, 1);
13095 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
13096 lon[ix], lat[iy], &h2o, ci, cw, 0);
13097 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
13098 lon[ix], lat[iy], &o3, ci, cw, 0);
13099
13100 /* Calculate volume mixing ratio... */
13101 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13102 vmr = MA / ctl->molmass * mass[idx3]
13103 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
13104
13105 /* Write output... */
13106 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
13107 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
13108 obsmean[idx2] / obscount[idx2], obscount[idx2]);
13109 }
13110 }
13111 }
13112
13113 /* Free... */
13114 free(mass);
13115 free(obsmean);
13116 free(obscount);
13117
13118 /* Finalize... */
13119 if (t == ctl->t_stop) {
13120
13121 /* Close output file... */
13122 fclose(out);
13123
13124 /* Free... */
13125 free(lon);
13126 free(lat);
13127 free(area);
13128 free(z);
13129 free(press);
13130 free(rt);
13131 free(rz);
13132 free(rlon);
13133 free(rlat);
13134 free(robs);
13135 }
13136}
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 13140 of file mptrac.c.

13146 {
13147
13148 static FILE *out;
13149
13150 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
13151 kw[EP];
13152
13153 static int nobs, nk;
13154
13155 /* Set timer... */
13156 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
13157
13158 /* Init... */
13159 if (t == ctl->t_start) {
13160
13161 /* Allocate... */
13162 ALLOC(rt, double,
13163 NOBS);
13164 ALLOC(rz, double,
13165 NOBS);
13166 ALLOC(rlon, double,
13167 NOBS);
13168 ALLOC(rlat, double,
13169 NOBS);
13170 ALLOC(robs, double,
13171 NOBS);
13172
13173 /* Read observation data... */
13174 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13175
13176 /* Read kernel data... */
13177 if (ctl->sample_kernel[0] != '-')
13178 read_kernel(ctl->sample_kernel, kz, kw, &nk);
13179
13180 /* Create output file... */
13181 LOG(1, "Write sample data: %s", filename);
13182 if (!(out = fopen(filename, "w")))
13183 ERRMSG("Cannot create file!");
13184
13185 /* Write header... */
13186 fprintf(out,
13187 "# $1 = time [s]\n"
13188 "# $2 = altitude [km]\n"
13189 "# $3 = longitude [deg]\n"
13190 "# $4 = latitude [deg]\n"
13191 "# $5 = surface area [km^2]\n"
13192 "# $6 = layer depth [km]\n"
13193 "# $7 = number of particles [1]\n"
13194 "# $8 = column density [kg/m^2]\n"
13195 "# $9 = volume mixing ratio [ppv]\n"
13196 "# $10 = observed BT index [K]\n\n");
13197
13198 /* Set latitude range, squared radius, and area... */
13199 dlat = DY2DEG(ctl->sample_dx);
13200 rmax2 = SQR(ctl->sample_dx);
13201 area = M_PI * rmax2;
13202 }
13203
13204 /* Set time interval for output... */
13205 const double t0 = t - 0.5 * ctl->dt_mod;
13206 const double t1 = t + 0.5 * ctl->dt_mod;
13207
13208 /* Loop over observations... */
13209 for (int i = 0; i < nobs; i++) {
13210
13211 /* Check time... */
13212 if (rt[i] < t0)
13213 continue;
13214 else if (rt[i] >= t1)
13215 break;
13216
13217 /* Calculate Cartesian coordinates... */
13218 double x0[3];
13219 geo2cart(0, rlon[i], rlat[i], x0);
13220
13221 /* Set pressure range... */
13222 const double rp = P(rz[i]);
13223 const double ptop = P(rz[i] + ctl->sample_dz);
13224 const double pbot = P(rz[i] - ctl->sample_dz);
13225
13226 /* Init... */
13227 double mass = 0;
13228 int np = 0;
13229
13230 /* Loop over air parcels... */
13231 //#pragma omp parallel for default(shared) reduction(+:mass,np)
13232 for (int ip = 0; ip < atm->np; ip++) {
13233
13234 /* Check time... */
13235 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13236 continue;
13237
13238 /* Check latitude... */
13239 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
13240 continue;
13241
13242 /* Check horizontal distance... */
13243 double x1[3];
13244 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13245 if (DIST2(x0, x1) > rmax2)
13246 continue;
13247
13248 /* Check pressure... */
13249 if (ctl->sample_dz > 0)
13250 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
13251 continue;
13252
13253 /* Add mass... */
13254 if (ctl->qnt_m >= 0)
13255 mass +=
13256 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13257 np++;
13258 }
13259
13260 /* Calculate column density... */
13261 const double cd = mass / (1e6 * area);
13262
13263 /* Calculate volume mixing ratio... */
13264 double vmr = 0;
13265 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
13266 if (mass > 0) {
13267
13268 /* Get temperature... */
13269 double temp;
13271 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
13272 rlon[i], rlat[i], &temp, ci, cw, 1);
13273
13274 /* Calculate volume mixing ratio... */
13275 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
13276 }
13277 } else
13278 vmr = NAN;
13279
13280 /* Write output... */
13281 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
13282 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
13283 }
13284
13285 /* Finalize...... */
13286 if (t == ctl->t_stop) {
13287
13288 /* Close output file... */
13289 fclose(out);
13290
13291 /* Free... */
13292 free(rt);
13293 free(rz);
13294 free(rlon);
13295 free(rlat);
13296 free(robs);
13297 }
13298}
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 13302 of file mptrac.c.

13306 {
13307
13308 static FILE *out;
13309
13310 static double rmax2, x0[3], x1[3];
13311
13312 /* Set timer... */
13313 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
13314
13315 /* Init... */
13316 if (t == ctl->t_start) {
13317
13318 /* Write info... */
13319 LOG(1, "Write station data: %s", filename);
13320
13321 /* Create new file... */
13322 if (!(out = fopen(filename, "w")))
13323 ERRMSG("Cannot create file!");
13324
13325 /* Write header... */
13326 fprintf(out,
13327 "# $1 = time [s]\n"
13328 "# $2 = altitude [km]\n"
13329 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13330 for (int iq = 0; iq < ctl->nq; iq++)
13331 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
13332 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13333 fprintf(out, "\n");
13334
13335 /* Set geolocation and search radius... */
13336 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
13337 rmax2 = SQR(ctl->stat_r);
13338 }
13339
13340 /* Set time interval for output... */
13341 const double t0 = t - 0.5 * ctl->dt_mod;
13342 const double t1 = t + 0.5 * ctl->dt_mod;
13343
13344 /* Loop over air parcels... */
13345 for (int ip = 0; ip < atm->np; ip++) {
13346
13347 /* Check time... */
13348 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13349 continue;
13350
13351 /* Check time range for station output... */
13352 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
13353 continue;
13354
13355 /* Check station flag... */
13356 if (ctl->qnt_stat >= 0)
13357 if ((int) atm->q[ctl->qnt_stat][ip])
13358 continue;
13359
13360 /* Get Cartesian coordinates... */
13361 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13362
13363 /* Check horizontal distance... */
13364 if (DIST2(x0, x1) > rmax2)
13365 continue;
13366
13367 /* Set station flag... */
13368 if (ctl->qnt_stat >= 0)
13369 atm->q[ctl->qnt_stat][ip] = 1;
13370
13371 /* Write data... */
13372 fprintf(out, "%.2f %g %g %g",
13373 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
13374 for (int iq = 0; iq < ctl->nq; iq++) {
13375 fprintf(out, " ");
13376 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
13377 }
13378 fprintf(out, "\n");
13379 }
13380
13381 /* Close file... */
13382 if (t == ctl->t_stop)
13383 fclose(out);
13384}
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 13388 of file mptrac.c.

13392 {
13393
13394 FILE *out;
13395
13396 /* Set timer... */
13397 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
13398
13399 /* Write info... */
13400 LOG(1, "Write VTK data: %s", filename);
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 /* Create file... */
13407 if (!(out = fopen(filename, "w")))
13408 ERRMSG("Cannot create file!");
13409
13410 /* Count data points... */
13411 int np = 0;
13412 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13413 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13414 continue;
13415 np++;
13416 }
13417
13418 /* Write header... */
13419 fprintf(out,
13420 "# vtk DataFile Version 3.0\n"
13421 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
13422
13423 /* Write point coordinates... */
13424 fprintf(out, "POINTS %d float\n", np);
13425 if (ctl->vtk_sphere) {
13426 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13427 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13428 continue;
13429 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
13430 + ctl->vtk_offset) / RE;
13431 const double coslat = cos(DEG2RAD(atm->lat[ip]));
13432 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
13433 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
13434 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
13435 fprintf(out, "%g %g %g\n", x, y, z);
13436 }
13437 } else
13438 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13439 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13440 continue;
13441 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
13442 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
13443 }
13444
13445 /* Write point data... */
13446 fprintf(out, "POINT_DATA %d\n", np);
13447 for (int iq = 0; iq < ctl->nq; iq++) {
13448 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
13449 ctl->qnt_name[iq]);
13450 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13451 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13452 continue;
13453 fprintf(out, "%g\n", atm->q[iq][ip]);
13454 }
13455 }
13456
13457 /* Close file... */
13458 fclose(out);
13459}