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_coord (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_3d_ml (const met_t *met, float zs[EX][EY][EP], float array[EX][EY][EP], const double z, const double lon, const double lat, double *var)
 Interpolates meteorological data 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_3d_ml (const met_t *met0, float zs0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float zs1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var)
 Interpolates meteorological data in both 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)
 Calculate grid data for chemistry modules. 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)
 Perform interparcel mixing for a specific 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)
 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)
 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)
 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)
 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)
 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_grid (const char *filename, const int ncid, const ctl_t *ctl, met_t *met)
 Reads meteorological grid information from a NetCDF file. More...
 
void read_met_levels (const int ncid, const ctl_t *ctl, met_t *met)
 Reads meteorological variables at different vertical levels 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, const clim_t *clim, met_t *met)
 Reads meteorological data from a NetCDF file and processes it. 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, 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, float dest[EX][EY][EP], const float scl)
 Reads a 3-dimensional meteorological variable from a NetCDF file. 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_surface (const int ncid, const ctl_t *ctl, met_t *met)
 Reads surface meteorological data from a netCDF file and stores it in the meteorological data structure. 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 = NORM(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:233
#define NORM(a)
Compute the norm (magnitude) of a vector.
Definition: mptrac.h:1258
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1407

◆ 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.
Authors
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 /* Apply diurnal correction... */
104 if (ctl->oh_chem_beta > 0) {
105 double sza = sza_calc(t, lon, lat);
106 if (sza <= sza_thresh)
107 return oh * exp(-ctl->oh_chem_beta / cos(sza));
108 else
109 return oh * exp(-ctl->oh_chem_beta / cos_sza_thresh);
110 } else
111 return oh;
112}
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:401
double sza_calc(const double sec, const double lon, const double lat)
Calculates the solar zenith angle.
Definition: mptrac.c:9162
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:489
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3355
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2871
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.
Authors
Lars Hoffmann
Mingzhao Liu

Definition at line 116 of file mptrac.c.

118 {
119
120 /* Set SZA threshold... */
121 const double sza_thresh = DEG2RAD(85.), cos_sza_thresh = cos(sza_thresh);
122
123 /* Loop over climatology data points... */
124 for (int it = 0; it < clim->oh.ntime; it++)
125 for (int iz = 0; iz < clim->oh.np; iz++)
126 for (int iy = 0; iy < clim->oh.nlat; iy++) {
127
128 /* Init... */
129 int n = 0;
130 double sum = 0;
131
132 /* Integrate day/night correction factor over longitude... */
133 for (double lon = -180; lon < 180; lon += 1.0) {
134 double sza = sza_calc(clim->oh.time[it], lon, clim->oh.lat[iy]);
135 if (sza <= sza_thresh)
136 sum += exp(-ctl->oh_chem_beta / cos(sza));
137 else
138 sum += exp(-ctl->oh_chem_beta / cos_sza_thresh);
139 n++;
140 }
141
142 /* Apply scaling factor to OH data... */
143 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
144 }
145}
double time[CT]
Time [s].
Definition: mptrac.h:3311
int np
Number of pressure levels.
Definition: mptrac.h:3308
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3320
int ntime
Number of timesteps.
Definition: mptrac.h:3302
int nlat
Number of latitudes.
Definition: mptrac.h:3305
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3314
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.
Authors
Lars Hoffmann
Mingzhao Liu

Definition at line 149 of file mptrac.c.

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

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

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

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

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

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

712 {
713
714 double min[EP], max[EP], off[EP], scl[EP];
715
716 unsigned short *sarray;
717
718 /* Allocate... */
719 ALLOC(sarray, unsigned short,
720 nxy * nz);
721
722 /* Read compressed stream and decompress array... */
723 if (decompress) {
724
725 /* Write info... */
726 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
727 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
728
729 /* Read data... */
730 FREAD(&scl, double,
731 nz,
732 inout);
733 FREAD(&off, double,
734 nz,
735 inout);
736 FREAD(sarray, unsigned short,
737 nxy * nz,
738 inout);
739
740 /* Convert to float... */
741#pragma omp parallel for default(shared)
742 for (size_t ixy = 0; ixy < nxy; ixy++)
743 for (size_t iz = 0; iz < nz; iz++)
744 array[ixy * nz + iz]
745 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
746 }
747
748 /* Compress array and output compressed stream... */
749 else {
750
751 /* Write info... */
752 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
753 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
754
755 /* Get range... */
756 for (size_t iz = 0; iz < nz; iz++) {
757 min[iz] = array[iz];
758 max[iz] = array[iz];
759 }
760 for (size_t ixy = 1; ixy < nxy; ixy++)
761 for (size_t iz = 0; iz < nz; iz++) {
762 if (array[ixy * nz + iz] < min[iz])
763 min[iz] = array[ixy * nz + iz];
764 if (array[ixy * nz + iz] > max[iz])
765 max[iz] = array[ixy * nz + iz];
766 }
767
768 /* Get offset and scaling factor... */
769 for (size_t iz = 0; iz < nz; iz++) {
770 scl[iz] = (max[iz] - min[iz]) / 65533.;
771 off[iz] = min[iz];
772 }
773
774 /* Convert to short... */
775#pragma omp parallel for default(shared)
776 for (size_t ixy = 0; ixy < nxy; ixy++)
777 for (size_t iz = 0; iz < nz; iz++)
778 if (scl[iz] != 0)
779 sarray[ixy * nz + iz] = (unsigned short)
780 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
781 else
782 sarray[ixy * nz + iz] = 0;
783
784 /* Write data... */
785 FWRITE(&scl, double,
786 nz,
787 inout);
788 FWRITE(&off, double,
789 nz,
790 inout);
791 FWRITE(sarray, unsigned short,
792 nxy * nz,
793 inout);
794 }
795
796 /* Free... */
797 free(sarray);
798}
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:678
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:658
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:360
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:272

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

946 {
947
948 const int
949 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
950 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
951
952 /* Get day of year... */
953 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
954 *doy = d0l[mon - 1] + day - 1;
955 else
956 *doy = d0[mon - 1] + day - 1;
957}

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

965 {
966
967 const int
968 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
969 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
970
971 int i;
972
973 /* Get month and day... */
974 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
975 for (i = 11; i > 0; i--)
976 if (d0l[i] <= doy)
977 break;
978 *mon = i + 1;
979 *day = doy - d0l[i] + 1;
980 } else {
981 for (i = 11; i > 0; i--)
982 if (d0[i] <= doy)
983 break;
984 *mon = i + 1;
985 *day = doy - d0[i] + 1;
986 }
987}

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

994 {
995
996 double data[2 * EX];
997
998 /* Check size... */
999 if (n > EX)
1000 ERRMSG("Too many data points!");
1001
1002 /* Allocate... */
1003 gsl_fft_complex_wavetable *wavetable =
1004 gsl_fft_complex_wavetable_alloc((size_t) n);
1005 gsl_fft_complex_workspace *workspace =
1006 gsl_fft_complex_workspace_alloc((size_t) n);
1007
1008 /* Set data (real, complex)... */
1009 for (int i = 0; i < n; i++) {
1010 data[2 * i] = fcReal[i];
1011 data[2 * i + 1] = fcImag[i];
1012 }
1013
1014 /* Calculate FFT... */
1015 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
1016
1017 /* Copy data... */
1018 for (int i = 0; i < n; i++) {
1019 fcReal[i] = data[2 * i];
1020 fcImag[i] = data[2 * i + 1];
1021 }
1022
1023 /* Free... */
1024 gsl_fft_complex_wavetable_free(wavetable);
1025 gsl_fft_complex_workspace_free(workspace);
1026}
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:1915
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:277

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

1034 {
1035
1036 const double radius = z + RE;
1037 const double latrad = DEG2RAD(lat);
1038 const double lonrad = DEG2RAD(lon);
1039 const double coslat = cos(latrad);
1040
1041 x[0] = radius * coslat * cos(lonrad);
1042 x[1] = radius * coslat * sin(lonrad);
1043 x[2] = radius * sin(latrad);
1044}

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

1054 {
1055
1056 char repl[LEN];
1057
1058 double t6, r;
1059
1060 int year, mon, day, hour, min, sec;
1061
1062 /* Round time to fixed intervals... */
1063 if (direct == -1)
1064 t6 = floor(t / dt_met) * dt_met;
1065 else
1066 t6 = ceil(t / dt_met) * dt_met;
1067
1068 /* Decode time... */
1069 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1070
1071 /* Set filename of MPTRAC meteo files... */
1072 if (ctl->met_clams == 0) {
1073 if (ctl->met_type == 0)
1074 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1075 else if (ctl->met_type == 1)
1076 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1077 else if (ctl->met_type == 2)
1078 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1079 else if (ctl->met_type == 3)
1080 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1081 else if (ctl->met_type == 4)
1082 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1083 else if (ctl->met_type == 5)
1084 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1085 sprintf(repl, "%d", year);
1086 get_met_replace(filename, "YYYY", repl);
1087 sprintf(repl, "%02d", mon);
1088 get_met_replace(filename, "MM", repl);
1089 sprintf(repl, "%02d", day);
1090 get_met_replace(filename, "DD", repl);
1091 sprintf(repl, "%02d", hour);
1092 get_met_replace(filename, "HH", repl);
1093 }
1094
1095 /* Set filename of CLaMS meteo files... */
1096 else {
1097 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1098 sprintf(repl, "%d", year);
1099 get_met_replace(filename, "YYYY", repl);
1100 sprintf(repl, "%02d", year % 100);
1101 get_met_replace(filename, "YY", repl);
1102 sprintf(repl, "%02d", mon);
1103 get_met_replace(filename, "MM", repl);
1104 sprintf(repl, "%02d", day);
1105 get_met_replace(filename, "DD", repl);
1106 sprintf(repl, "%02d", hour);
1107 get_met_replace(filename, "HH", repl);
1108 }
1109}
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:1113
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:1740
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:252
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2497
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=zfp, 4=zstd, 5=cms).
Definition: mptrac.h:2494
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 1113 of file mptrac.c.

1116 {
1117
1118 char buffer[LEN];
1119
1120 /* Iterate... */
1121 for (int i = 0; i < 3; i++) {
1122
1123 /* Replace sub-string... */
1124 char *ch;
1125 if (!(ch = strstr(orig, search)))
1126 return;
1127 strncpy(buffer, orig, (size_t) (ch - orig));
1128 buffer[ch - orig] = 0;
1129 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1130 orig[0] = 0;
1131 strcpy(orig, buffer);
1132 }
1133}

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

1152 {
1153
1155
1156 ctl->met_tropo = met_tropo;
1157 read_met_tropo(ctl, clim, met);
1158#pragma omp parallel for default(shared) private(ci,cw)
1159 for (int ix = 0; ix < nx; ix++)
1160 for (int iy = 0; iy < ny; iy++) {
1161 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1162 &pt[iy * nx + ix], ci, cw, 1);
1163 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1164 &ps[iy * nx + ix], ci, cw, 0);
1165 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1166 &zs[iy * nx + ix], ci, cw, 0);
1167 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1168 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1169 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1170 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1171 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1172 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1173 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1174 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1175 }
1176}
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:1504
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:8716
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:1379
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:693
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2631
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3510
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3420
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3426
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3513
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3495
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3453
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3492
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 1180 of file mptrac.c.

1188 {
1189
1190 /* Check longitude... */
1191 *lon2 = FMOD(lon, 360.);
1192 if (*lon2 < lons[0])
1193 *lon2 += 360;
1194 else if (*lon2 > lons[nlon - 1])
1195 *lon2 -= 360;
1196
1197 /* Check latitude... */
1198 *lat2 = lat;
1199 if (lats[0] < lats[nlat - 1])
1200 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
1201 else
1202 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
1203}

◆ intpol_met_4d_coord()

void intpol_met_4d_coord ( 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 1207 of file mptrac.c.

1221 {
1222
1223 if (init) {
1224
1225 /* Check longitude and latitude... */
1226 double lon2, lat2;
1227 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
1228 &lon2, &lat2);
1229
1230 /* Get horizontal indizes... */
1231 ci[0] = locate_irr(met0->lon, met0->nx, lon2);
1232 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
1233
1234 /* Locate the vertical indizes for each edge of the column... */
1235 int ind[2][4];
1236 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1237 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1238
1239 /* Find minimum and maximum indizes... */
1240 ci[2] = ind[0][0];
1241 int k_max = ind[0][0];
1242 for (int i = 0; i < 2; i++)
1243 for (int j = 0; j < 4; j++) {
1244 if (ci[2] > ind[i][j])
1245 ci[2] = ind[i][j];
1246 if (k_max < ind[i][j])
1247 k_max = ind[i][j];
1248 }
1249
1250 /* Get weighting factors for time, longitude and latitude... */
1251 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1252 cw[0] = (lon2 - met0->lon[ci[0]]) /
1253 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1254 cw[1] = (lat2 - met0->lat[ci[1]]) /
1255 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1256
1257 /* Interpolate in time at the lowest level... */
1258 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1259 - heights0[ci[0]][ci[1]][ci[2]])
1260 + heights0[ci[0]][ci[1]][ci[2]];
1261 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1262 - heights0[ci[0]][ci[1] + 1][ci[2]])
1263 + heights0[ci[0]][ci[1] + 1][ci[2]];
1264 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1265 - heights0[ci[0] + 1][ci[1]][ci[2]])
1266 + heights0[ci[0] + 1][ci[1]][ci[2]];
1267 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1268 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1269 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1270
1271 /* Interpolate in latitude direction... */
1272 double height0 = cw[1] * (height01 - height00) + height00;
1273 double height1 = cw[1] * (height11 - height10) + height10;
1274
1275 /* Interpolate in longitude direction... */
1276 double height_bot = cw[0] * (height1 - height0) + height0;
1277
1278 /* Interpolate in time at the upper level... */
1279 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1280 - heights0[ci[0]][ci[1]][ci[2] + 1])
1281 + heights0[ci[0]][ci[1]][ci[2] + 1];
1282 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1283 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1284 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1285 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1286 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1287 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1288 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1289 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1290 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1291
1292 /* Interpolate in latitude direction... */
1293 height0 = cw[1] * (height01 - height00) + height00;
1294 height1 = cw[1] * (height11 - height10) + height10;
1295
1296 /* Interpolate in longitude direction... */
1297 double height_top = cw[0] * (height1 - height0) + height0;
1298
1299 /* Search at higher levels if height is not in box... */
1300 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1301 ((height_bot <= height) || (height_top > height))
1302 && (height_bot >= height) && (ci[2] < k_max))
1303 ||
1304 ((heights0[0][0][0] < heights0[0][0][1]) &&
1305 ((height_bot >= height) || (height_top < height))
1306 && (height_bot <= height) && (ci[2] < k_max))
1307 ) {
1308
1309 ci[2]++;
1310 height_bot = height_top;
1311
1312 /* Interpolate in time at the next level... */
1313 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1314 - heights0[ci[0]][ci[1]][ci[2] + 1])
1315 + heights0[ci[0]][ci[1]][ci[2] + 1];
1316 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1317 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1318 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1319 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1320 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1321 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1322 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1323 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1324 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1325
1326 /* Interpolate in latitude direction... */
1327 height0 = cw[1] * (height01 - height00) + height00;
1328 height1 = cw[1] * (height11 - height10) + height10;
1329
1330 /* Interpolate in longitude direction... */
1331 height_top = cw[0] * (height1 - height0) + height0;
1332 }
1333
1334 /* Get vertical weighting factors... */
1335 cw[2] = (height - height_bot)
1336 / (height_top - height_bot);
1337 }
1338
1339 /* Calculate the needed array values... */
1340 double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1341 - array0[ci[0]][ci[1]][ci[2]])
1342 + array0[ci[0]][ci[1]][ci[2]];
1343 double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1344 - array0[ci[0] + 1][ci[1]][ci[2]])
1345 + array0[ci[0] + 1][ci[1]][ci[2]];
1346 double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1347 - array0[ci[0]][ci[1] + 1][ci[2]])
1348 + array0[ci[0]][ci[1] + 1][ci[2]];
1349 double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1350 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1351 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1352 double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1353 - array0[ci[0]][ci[1]][ci[2] + 1])
1354 + array0[ci[0]][ci[1]][ci[2] + 1];
1355 double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
1356 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
1357 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
1358 double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
1359 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
1360 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
1361 double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1362 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1363 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1364
1365 double array00 = cw[0] * (array100 - array000) + array000;
1366 double array10 = cw[0] * (array110 - array010) + array010;
1367 double array01 = cw[0] * (array101 - array001) + array001;
1368 double array11 = cw[0] * (array111 - array011) + array011;
1369
1370 double aux0 = cw[1] * (array10 - array00) + array00;
1371 double aux1 = cw[1] * (array11 - array01) + array01;
1372
1373 /* Interpolate vertically... */
1374 *var = cw[2] * (aux1 - aux0) + aux0;
1375}
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:2110
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:1180
int nx
Number of longitudes.
Definition: mptrac.h:3396
int ny
Number of latitudes.
Definition: mptrac.h:3399
double lon[EX]
Longitude [deg].
Definition: mptrac.h:3408
int npl
Number of model levels.
Definition: mptrac.h:3405
double time
Time [s].
Definition: mptrac.h:3393
double lat[EY]
Latitude [deg].
Definition: mptrac.h:3411
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 1379 of file mptrac.c.

1388 {
1389
1390 /* Initialize interpolation... */
1391 if (init) {
1392
1393 /* Check longitude and latitude... */
1394 double lon2, lat2;
1395 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1396 &lon2, &lat2);
1397
1398 /* Get interpolation indices... */
1399 ci[0] = locate_irr(met->p, met->np, p);
1400 ci[1] = locate_reg(met->lon, met->nx, lon2);
1401 ci[2] = locate_irr(met->lat, met->ny, lat2);
1402
1403 /* Get interpolation weights... */
1404 cw[0] = (met->p[ci[0] + 1] - p)
1405 / (met->p[ci[0] + 1] - met->p[ci[0]]);
1406 cw[1] = (met->lon[ci[1] + 1] - lon2)
1407 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1408 cw[2] = (met->lat[ci[2] + 1] - lat2)
1409 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1410 }
1411
1412 /* Interpolate vertically... */
1413 double aux00 =
1414 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
1415 + array[ci[1]][ci[2]][ci[0] + 1];
1416 double aux01 =
1417 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
1418 array[ci[1]][ci[2] + 1][ci[0] + 1])
1419 + array[ci[1]][ci[2] + 1][ci[0] + 1];
1420 double aux10 =
1421 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
1422 array[ci[1] + 1][ci[2]][ci[0] + 1])
1423 + array[ci[1] + 1][ci[2]][ci[0] + 1];
1424 double aux11 =
1425 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
1426 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
1427 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
1428
1429 /* Interpolate horizontally... */
1430 aux00 = cw[2] * (aux00 - aux01) + aux01;
1431 aux11 = cw[2] * (aux10 - aux11) + aux11;
1432 *var = cw[1] * (aux00 - aux11) + aux11;
1433}
int np
Number of pressure levels.
Definition: mptrac.h:3402
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3414
Here is the call graph for this function:

◆ intpol_met_space_3d_ml()

void intpol_met_space_3d_ml ( const met_t met,
float  zs[EX][EY][EP],
float  vals[EX][EY][EP],
const double  z,
const double  lon,
const double  lat,
double *  val 
)

Interpolates meteorological data in 3D space.

This function performs trilinear interpolation to estimate a meteorological variable at a given altitude (z), longitude (lon), and latitude (lat). It uses a structured 3D grid with irregular vertical spacing and regular horizontal spacing.

Parameters
metPointer to the meteorological data structure containing grid information.
zs3D array of altitude levels at each horizontal grid point.
array3D array of meteorological data values corresponding to the grid points.
zTarget altitude for interpolation.
lonTarget longitude for interpolation.
latTarget latitude for interpolation.
varPointer to a variable where the interpolated value will be stored.
Author
Lars Hoffmann

Definition at line 1437 of file mptrac.c.

1444 {
1445
1446 /* Check longitude and latitude... */
1447 double lon2, lat2;
1448 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat, &lon2,
1449 &lat2);
1450
1451 /* Get horizontal indices... */
1452 const int ix = locate_reg(met->lon, met->nx, lon2);
1453 const int iy = locate_irr(met->lat, met->ny, lat2);
1454
1455 /* Interpolate vertically... */
1456 int iz = locate_irr_float(zs[ix][iy], met->npl, z, 0);
1457 double aux00;
1458 if (z >= zs[ix][iy][iz + 1])
1459 aux00 = array[ix][iy][iz + 1];
1460 else if (z <= zs[ix][iy][iz])
1461 aux00 = array[ix][iy][iz];
1462 else
1463 aux00 = LIN(zs[ix][iy][iz], array[ix][iy][iz],
1464 zs[ix][iy][iz + 1], array[ix][iy][iz + 1], z);
1465
1466 iz = locate_irr_float(zs[ix][iy + 1], met->npl, z, iz);
1467 double aux01;
1468 if (z >= zs[ix][iy + 1][iz + 1])
1469 aux01 = array[ix][iy + 1][iz + 1];
1470 else if (z <= zs[ix][iy + 1][iz])
1471 aux01 = array[ix][iy + 1][iz];
1472 else
1473 aux01 = LIN(zs[ix][iy + 1][iz], array[ix][iy + 1][iz],
1474 zs[ix][iy + 1][iz + 1], array[ix][iy + 1][iz + 1], z);
1475
1476 iz = locate_irr_float(zs[ix + 1][iy], met->npl, z, iz);
1477 double aux10;
1478 if (z >= zs[ix + 1][iy][iz + 1])
1479 aux10 = array[ix + 1][iy][iz + 1];
1480 else if (z <= zs[ix + 1][iy][iz])
1481 aux10 = array[ix + 1][iy][iz];
1482 else
1483 aux10 = LIN(zs[ix + 1][iy][iz], array[ix + 1][iy][iz],
1484 zs[ix + 1][iy][iz + 1], array[ix + 1][iy][iz + 1], z);
1485
1486 iz = locate_irr_float(zs[ix + 1][iy + 1], met->npl, z, iz);
1487 double aux11;
1488 if (z >= zs[ix + 1][iy + 1][iz + 1])
1489 aux11 = array[ix + 1][iy + 1][iz + 1];
1490 else if (z <= zs[ix + 1][iy + 1][iz])
1491 aux11 = array[ix + 1][iy + 1][iz];
1492 else
1493 aux11 = LIN(zs[ix + 1][iy + 1][iz], array[ix + 1][iy + 1][iz],
1494 zs[ix + 1][iy + 1][iz + 1], array[ix + 1][iy + 1][iz + 1], z);
1495
1496 /* Interpolate horizontally... */
1497 double aux0 = LIN(met->lat[iy], aux00, met->lat[iy + 1], aux01, lat2);
1498 double aux1 = LIN(met->lat[iy], aux10, met->lat[iy + 1], aux11, lat2);
1499 *var = LIN(met->lon[ix], aux0, met->lon[ix + 1], aux1, lon2);
1500}
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:2057
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 1504 of file mptrac.c.

1512 {
1513
1514 /* Initialize interpolation... */
1515 if (init) {
1516
1517 /* Check longitude and latitude... */
1518 double lon2, lat2;
1519 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1520 &lon2, &lat2);
1521
1522 /* Get interpolation indices... */
1523 ci[1] = locate_reg(met->lon, met->nx, lon2);
1524 ci[2] = locate_irr(met->lat, met->ny, lat2);
1525
1526 /* Get interpolation weights... */
1527 cw[1] = (met->lon[ci[1] + 1] - lon2)
1528 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1529 cw[2] = (met->lat[ci[2] + 1] - lat2)
1530 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1531 }
1532
1533 /* Set variables... */
1534 double aux00 = array[ci[1]][ci[2]];
1535 double aux01 = array[ci[1]][ci[2] + 1];
1536 double aux10 = array[ci[1] + 1][ci[2]];
1537 double aux11 = array[ci[1] + 1][ci[2] + 1];
1538
1539 /* Interpolate horizontally... */
1540 if (isfinite(aux00) && isfinite(aux01)
1541 && isfinite(aux10) && isfinite(aux11)) {
1542 aux00 = cw[2] * (aux00 - aux01) + aux01;
1543 aux11 = cw[2] * (aux10 - aux11) + aux11;
1544 *var = cw[1] * (aux00 - aux11) + aux11;
1545 } else {
1546 if (cw[2] < 0.5) {
1547 if (cw[1] < 0.5)
1548 *var = aux11;
1549 else
1550 *var = aux01;
1551 } else {
1552 if (cw[1] < 0.5)
1553 *var = aux10;
1554 else
1555 *var = aux00;
1556 }
1557 }
1558}
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 1562 of file mptrac.c.

1574 {
1575
1576 double var0, var1;
1577
1578 /* Spatial interpolation... */
1579 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
1580 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
1581
1582 /* Get weighting factor... */
1583 const double wt = (met1->time - ts) / (met1->time - met0->time);
1584
1585 /* Interpolate... */
1586 *var = wt * (var0 - var1) + var1;
1587}
Here is the call graph for this function:

◆ intpol_met_time_3d_ml()

void intpol_met_time_3d_ml ( const met_t met0,
float  zs0[EX][EY][EP],
float  array0[EX][EY][EP],
const met_t met1,
float  zs1[EX][EY][EP],
float  array1[EX][EY][EP],
const double  ts,
const double  p,
const double  lon,
const double  lat,
double *  var 
)

Interpolates meteorological data in both space and time.

This function performs 3D spatial interpolation at two time steps (met0 and met1), then interpolates the results in time to estimate the meteorological variable at a given time (ts), pressure level (p), longitude (lon), and latitude (lat).

Parameters
met0Pointer to the meteorological data structure at the earlier time step.
zs03D array of altitude levels for met0.
array03D array of meteorological data values corresponding to met0.
met1Pointer to the meteorological data structure at the later time step.
zs13D array of altitude levels for met1.
array13D array of meteorological data values corresponding to met1.
tsTarget time for interpolation.
pTarget pressure level for interpolation.
lonTarget longitude for interpolation.
latTarget latitude for interpolation.
varPointer to a variable where the interpolated value will be stored.
Author
Lars Hoffmann

Definition at line 1591 of file mptrac.c.

1602 {
1603
1604 double var0, var1;
1605
1606 /* Spatial interpolation... */
1607 intpol_met_space_3d_ml(met0, zs0, array0, p, lon, lat, &var0);
1608 intpol_met_space_3d_ml(met1, zs1, array1, p, lon, lat, &var1);
1609
1610 /* Interpolate... */
1611 *var = LIN(met0->time, var0, met1->time, var1, ts);
1612}
void intpol_met_space_3d_ml(const met_t *met, float zs[EX][EY][EP], float array[EX][EY][EP], const double z, const double lon, const double lat, double *var)
Interpolates meteorological data in 3D space.
Definition: mptrac.c:1437
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 1616 of file mptrac.c.

1627 {
1628
1629 double var0, var1;
1630
1631 /* Spatial interpolation... */
1632 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
1633 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
1634
1635 /* Get weighting factor... */
1636 const double wt = (met1->time - ts) / (met1->time - met0->time);
1637
1638 /* Interpolate... */
1639 if (isfinite(var0) && isfinite(var1))
1640 *var = wt * (var0 - var1) + var1;
1641 else if (wt < 0.5)
1642 *var = var1;
1643 else
1644 *var = var0;
1645}
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 1649 of file mptrac.c.

1663 {
1664
1665 double aux0, aux1, aux00, aux01, aux10, aux11, mean = 0;
1666
1667 int n = 0;
1668
1669 /* Check longitude and latitude... */
1670 double lon2, lat2;
1671 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
1672
1673 /* Get indices... */
1674 const int ix = locate_reg(lons, (int) nlon, lon2);
1675 const int iy = locate_irr(lats, (int) nlat, lat2);
1676
1677 /* Calculate standard deviation... */
1678 *sigma = 0;
1679 for (int dx = 0; dx < 2; dx++)
1680 for (int dy = 0; dy < 2; dy++) {
1681 if (isfinite(array0[ix + dx][iy + dy])) {
1682 mean += array0[ix + dx][iy + dy];
1683 *sigma += SQR(array0[ix + dx][iy + dy]);
1684 n++;
1685 }
1686 if (isfinite(array1[ix + dx][iy + dy])) {
1687 mean += array1[ix + dx][iy + dy];
1688 *sigma += SQR(array1[ix + dx][iy + dy]);
1689 n++;
1690 }
1691 }
1692 if (n > 0)
1693 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
1694
1695 /* Linear interpolation... */
1696 if (method == 1 && isfinite(array0[ix][iy])
1697 && isfinite(array0[ix][iy + 1])
1698 && isfinite(array0[ix + 1][iy])
1699 && isfinite(array0[ix + 1][iy + 1])
1700 && isfinite(array1[ix][iy])
1701 && isfinite(array1[ix][iy + 1])
1702 && isfinite(array1[ix + 1][iy])
1703 && isfinite(array1[ix + 1][iy + 1])) {
1704
1705 aux00 = LIN(lons[ix], array0[ix][iy],
1706 lons[ix + 1], array0[ix + 1][iy], lon2);
1707 aux01 = LIN(lons[ix], array0[ix][iy + 1],
1708 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1709 aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1710
1711 aux10 = LIN(lons[ix], array1[ix][iy],
1712 lons[ix + 1], array1[ix + 1][iy], lon2);
1713 aux11 = LIN(lons[ix], array1[ix][iy + 1],
1714 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1715 aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1716
1717 *var = LIN(time0, aux0, time1, aux1, time);
1718 }
1719
1720 /* Nearest neighbor interpolation... */
1721 else {
1722 aux00 = NN(lons[ix], array0[ix][iy],
1723 lons[ix + 1], array0[ix + 1][iy], lon2);
1724 aux01 = NN(lons[ix], array0[ix][iy + 1],
1725 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1726 aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1727
1728 aux10 = NN(lons[ix], array1[ix][iy],
1729 lons[ix + 1], array1[ix + 1][iy], lon2);
1730 aux11 = NN(lons[ix], array1[ix][iy + 1],
1731 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1732 aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1733
1734 *var = NN(time0, aux0, time1, aux1, time);
1735 }
1736}
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1243
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1568
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 1740 of file mptrac.c.

1748 {
1749
1750 struct tm t0, *t1;
1751
1752 t0.tm_year = 100;
1753 t0.tm_mon = 0;
1754 t0.tm_mday = 1;
1755 t0.tm_hour = 0;
1756 t0.tm_min = 0;
1757 t0.tm_sec = 0;
1758
1759 const time_t jsec0 = (time_t) jsec + timegm(&t0);
1760 t1 = gmtime(&jsec0);
1761
1762 *year = t1->tm_year + 1900;
1763 *mon = t1->tm_mon + 1;
1764 *day = t1->tm_mday;
1765 *hour = t1->tm_hour;
1766 *min = t1->tm_min;
1767 *sec = t1->tm_sec;
1768 *remain = jsec - floor(jsec);
1769}

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

1777 {
1778
1779 /* Check number of data points... */
1780 if (nk < 2)
1781 return 1.0;
1782
1783 /* Get altitude... */
1784 const double z = Z(p);
1785
1786 /* Get weighting factor... */
1787 if (z < kz[0])
1788 return kw[0];
1789 else if (z > kz[nk - 1])
1790 return kw[nk - 1];
1791 else {
1792 int idx = locate_irr(kz, nk, z);
1793 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
1794 }
1795}
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 1799 of file mptrac.c.

1801 {
1802
1803 /*
1804 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
1805 and water vapor volume mixing ratio [1].
1806
1807 Reference: https://en.wikipedia.org/wiki/Lapse_rate
1808 */
1809
1810 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
1811
1812 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
1813}
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:228
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1555
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:193
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:183
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:178
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:173

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

1818 {
1819
1820 if (0 == ctl->met_press_level_def) {
1821
1822 ctl->met_np = 138;
1823
1824 const double press[138] = {
1825 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1826 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1827 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1828 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1829 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1830 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1831 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1832 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1833 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1834 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1835 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1836 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1837 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1838 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1839 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1840 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1841 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1842 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1843 1010.8487, 1013.2500, 1044.45
1844 };
1845
1846 for (int ip = 0; ip < ctl->met_np; ip++)
1847 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1848
1849 } else if (1 == ctl->met_press_level_def) {
1850
1851 ctl->met_np = 92;
1852
1853 const double press[92] = {
1854 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1855 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1856 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1857 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1858 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1859 113.6382,
1860 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1861 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1862 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1863 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1864 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1865 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1866 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1867 1007.4431, 1010.8487, 1013.2500, 1044.45
1868 };
1869
1870 for (int ip = 0; ip < ctl->met_np; ip++)
1871 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1872
1873 } else if (2 == ctl->met_press_level_def) {
1874
1875 ctl->met_np = 60;
1876
1877 const double press[60] = {
1878 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1879 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1880 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1881 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1882 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1883 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1884 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1885 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
1886 };
1887
1888 for (int ip = 0; ip < ctl->met_np; ip++)
1889 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1890
1891 } else if (3 == ctl->met_press_level_def) {
1892
1893 ctl->met_np = 147;
1894
1895 const double press[147] = {
1896 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1897 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1898 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1899 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1900 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1901 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1902 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1903 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1904 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1905 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1906 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1907 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1908 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1909 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1910 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1911 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1912 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1913 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1914 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
1915 1031.97,
1916 1035.09, 1038.21, 1041.33, 1044.45
1917 };
1918
1919 for (int ip = 0; ip < ctl->met_np; ip++)
1920 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1921
1922 } else if (4 == ctl->met_press_level_def) {
1923
1924 ctl->met_np = 101;
1925
1926 const double press[101] = {
1927 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1928 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1929 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1930 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1931 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1932 113.6382,
1933 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1934 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1935 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1936 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1937 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1938 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1939 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1940 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
1941 1028.85, 1031.97,
1942 1035.09, 1038.21, 1041.33, 1044.45
1943 };
1944
1945 for (int ip = 0; ip < ctl->met_np; ip++)
1946 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1947
1948 } else if (5 == ctl->met_press_level_def) {
1949
1950 ctl->met_np = 62;
1951
1952 const double press[62] = {
1953 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1954 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1955 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1956 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1957 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1958 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1959 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1960 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
1961 1044.45
1962 };
1963
1964 for (int ip = 0; ip < ctl->met_np; ip++)
1965 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1966
1967 } else if (6 == ctl->met_press_level_def) {
1968
1969 ctl->met_np = 137;
1970
1971 const double press[137] = {
1972 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
1973 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
1974 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
1975 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
1976 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
1977 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1978 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
1979 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
1980 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
1981 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
1982 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
1983 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
1984 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
1985 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
1986 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
1987 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
1988 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
1989 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
1990 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
1991 1030.06, 1037.25, 1044.45
1992 };
1993
1994 for (int ip = 0; ip < ctl->met_np; ip++)
1995 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1996
1997 } else if (7 == ctl->met_press_level_def) {
1998
1999 ctl->met_np = 59;
2000
2001 const double press[59] = {
2002 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2003 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2004 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2005 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2006 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2007 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2008 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2009 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2010 1028.53, 1046.13
2011 };
2012
2013 for (int ip = 0; ip < ctl->met_np; ip++)
2014 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2015
2016 } else {
2017 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.")
2018 }
2019
2020 if (ctl->met_np > NP)
2021 ERRMSG("Recompile with larger NP to use this pressure level definition.")
2022
2023}
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:257
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2597
int met_np
Number of target pressure levels.
Definition: mptrac.h:2591
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2594

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

2030 {
2031
2032 int ilo = 0;
2033 int ihi = n - 1;
2034 int i = (ihi + ilo) >> 1;
2035
2036 if (xx[i] < xx[i + 1])
2037 while (ihi > ilo + 1) {
2038 i = (ihi + ilo) >> 1;
2039 if (xx[i] > x)
2040 ihi = i;
2041 else
2042 ilo = i;
2043 } else
2044 while (ihi > ilo + 1) {
2045 i = (ihi + ilo) >> 1;
2046 if (xx[i] <= x)
2047 ihi = i;
2048 else
2049 ilo = i;
2050 }
2051
2052 return ilo;
2053}

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

2061 {
2062
2063 int ilo = 0;
2064 int ihi = n - 1;
2065 int i = (ihi + ilo) >> 1;
2066
2067 if (x >= xx[ig] && x < xx[ig + 1])
2068 return ig;
2069
2070 if (xx[i] < xx[i + 1])
2071 while (ihi > ilo + 1) {
2072 i = (ihi + ilo) >> 1;
2073 if (xx[i] > x)
2074 ihi = i;
2075 else
2076 ilo = i;
2077 } else
2078 while (ihi > ilo + 1) {
2079 i = (ihi + ilo) >> 1;
2080 if (xx[i] <= x)
2081 ihi = i;
2082 else
2083 ilo = i;
2084 }
2085
2086 return ilo;
2087}

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

2094 {
2095
2096 /* Calculate index... */
2097 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2098
2099 /* Check range... */
2100 if (i < 0)
2101 return 0;
2102 else if (i > n - 2)
2103 return n - 2;
2104 else
2105 return i;
2106}

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

2116 {
2117
2118 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2119 np, height_ap, 0);
2120 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2121 np, height_ap, ind[0]);
2122 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2123 np, height_ap, ind[1]);
2124 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2125 np, height_ap, ind[2]);
2126}
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.
Authors
Lars Hoffmann
Jan Clemens

Definition at line 2130 of file mptrac.c.

2135 {
2136
2137 /* Set timer... */
2138 SELECT_TIMER("MODULE_ADVECT", "PHYSICS", NVTX_GPU);
2139
2140 /* Use omega vertical velocity... */
2141 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2142
2143 /* Loop over particles... */
2144 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2145
2146 /* Init... */
2148 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2149 x[3] = { 0, 0, 0 };
2150
2151 /* Loop over integration nodes... */
2152 for (int i = 0; i < ctl->advect; i++) {
2153
2154 /* Set position... */
2155 if (i == 0) {
2156 dts = 0.0;
2157 x[0] = atm->lon[ip];
2158 x[1] = atm->lat[ip];
2159 x[2] = atm->p[ip];
2160 } else {
2161 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2162 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2163 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2164 x[2] = atm->p[ip] + dts * w[i - 1];
2165 }
2166 const double tm = atm->time[ip] + dts;
2167
2168 /* Interpolate meteo data on pressure levels... */
2169 if (ctl->advect_vert_coord == 0) {
2170 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2171 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2172 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2173 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2174 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2175 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2176 }
2177
2178 /* Interpolate meteo data on model levels... */
2179 else {
2180 intpol_met_time_3d_ml(met0, met0->pl, met0->ul,
2181 met1, met1->pl, met1->ul,
2182 tm, x[2], x[0], x[1], &u[i]);
2183 intpol_met_time_3d_ml(met0, met0->pl, met0->vl,
2184 met1, met1->pl, met1->vl,
2185 tm, x[2], x[0], x[1], &v[i]);
2186 intpol_met_time_3d_ml(met0, met0->pl, met0->wl,
2187 met1, met1->pl, met1->wl,
2188 tm, x[2], x[0], x[1], &w[i]);
2189 }
2190
2191 /* Get mean wind... */
2192 double k = 1.0;
2193 if (ctl->advect == 2)
2194 k = (i == 0 ? 0.0 : 1.0);
2195 else if (ctl->advect == 4)
2196 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2197 um += k * u[i];
2198 vm += k * v[i];
2199 wm += k * w[i];
2200 }
2201
2202 /* Set new position... */
2203 atm->time[ip] += cache->dt[ip];
2204 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2205 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2206 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2207 atm->p[ip] += cache->dt[ip] * wm;
2208 }
2209 }
2210
2211 /* Use zetadot vertical velocity... */
2212 else if (ctl->advect_vert_coord == 1) {
2213
2214 /* Loop over particles... */
2215 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2216
2217 /* Convert pressure to zeta... */
2219 intpol_met_4d_coord(met0, met0->pl, met0->zetal, met1,
2220 met1->pl, met1->zetal, atm->time[ip], atm->p[ip],
2221 atm->lon[ip], atm->lat[ip],
2222 &atm->q[ctl->qnt_zeta][ip], ci, cw, 1);
2223
2224 /* Init... */
2225 double dts, u[4], um = 0, v[4], vm = 0, zeta_dot[4],
2226 zeta_dotm = 0, x[3] = { 0, 0, 0 };
2227
2228 /* Loop over integration nodes... */
2229 for (int i = 0; i < ctl->advect; i++) {
2230
2231 /* Set position... */
2232 if (i == 0) {
2233 dts = 0.0;
2234 x[0] = atm->lon[ip];
2235 x[1] = atm->lat[ip];
2236 x[2] = atm->q[ctl->qnt_zeta][ip];
2237 } else {
2238 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2239 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2240 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2241 x[2] = atm->q[ctl->qnt_zeta][ip] + dts * zeta_dot[i - 1];
2242 }
2243 const double tm = atm->time[ip] + dts;
2244
2245 /* Interpolate meteo data... */
2246 intpol_met_4d_coord(met0, met0->zetal, met0->ul, met1, met1->zetal,
2247 met1->ul, tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2248 intpol_met_4d_coord(met0, met0->zetal, met0->vl, met1, met1->zetal,
2249 met1->vl, tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2250 intpol_met_4d_coord(met0, met0->zetal, met0->zeta_dotl, met1,
2251 met1->zetal, met1->zeta_dotl, tm, x[2], x[0],
2252 x[1], &zeta_dot[i], ci, cw, 0);
2253
2254 /* Get mean wind... */
2255 double k = 1.0;
2256 if (ctl->advect == 2)
2257 k = (i == 0 ? 0.0 : 1.0);
2258 else if (ctl->advect == 4)
2259 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2260 um += k * u[i];
2261 vm += k * v[i];
2262 zeta_dotm += k * zeta_dot[i];
2263 }
2264
2265 /* Set new position... */
2266 atm->time[ip] += cache->dt[ip];
2267 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2268 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2269 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2270 atm->q[ctl->qnt_zeta][ip] += cache->dt[ip] * zeta_dotm;
2271
2272 /* Convert zeta to pressure... */
2273 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2274 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2275 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2276 }
2277 }
2278}
void intpol_met_4d_coord(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:1207
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:1562
void intpol_met_time_3d_ml(const met_t *met0, float zs0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float zs1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var)
Interpolates meteorological data in both space and time.
Definition: mptrac.c:1591
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1285
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:536
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:1995
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:554
double time[NP]
Time [s].
Definition: mptrac.h:3169
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3178
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3175
int np
Number of air parcels.
Definition: mptrac.h:3166
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3181
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3172
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3212
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2666
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2383
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev).
Definition: mptrac.h:2670
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3546
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3504
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3540
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3537
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3498
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3534
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3501
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3531
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3543
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 2282 of file mptrac.c.

2287 {
2288
2289 /* Check parameters... */
2290 if (ctl->advect_vert_coord != 1)
2291 return;
2292
2293 /* Set timer... */
2294 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS", NVTX_GPU);
2295
2296 /* Loop over particles... */
2297 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
2298
2299 /* Initialize pressure consistent with zeta... */
2301 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2302 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2303 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2304 }
2305}
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.
Authors
Lars Hoffmann
Mingzhao Liu

Definition at line 2309 of file mptrac.c.

2315 {
2316
2317 /* Set timer... */
2318 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS", NVTX_GPU);
2319
2320 /* Check quantity flags... */
2321 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2322 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2323 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2324 return;
2325
2326 /* Loop over particles... */
2327 PARTICLE_LOOP(0, atm->np, 1,
2328 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2329
2330 /* Check latitude and pressure range... */
2331 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2332 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2333 continue;
2334
2335 /* Check surface layer... */
2336 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2337 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2338
2339 /* Get surface pressure... */
2340 double ps;
2342 INTPOL_2D(ps, 1);
2343
2344 /* Check pressure... */
2345 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2346 continue;
2347
2348 /* Check height... */
2349 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2350 continue;
2351
2352 /* Check zeta range... */
2353 if (ctl->bound_zetas > 0) {
2354 double t;
2355 INTPOL_3D(t, 1);
2356 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2357 continue;
2358 }
2359
2360 /* Check planetary boundary layer... */
2361 if (ctl->bound_pbl) {
2362 double pbl;
2363 INTPOL_2D(pbl, 0);
2364 if (atm->p[ip] < pbl)
2365 continue;
2366 }
2367 }
2368
2369 /* Set mass and volume mixing ratio... */
2370 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2371 atm->q[ctl->qnt_m][ip] =
2372 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2373 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2374 atm->q[ctl->qnt_vmr][ip] =
2375 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2376
2377 /* Set CFC-10 volume mixing ratio... */
2378 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2379 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2380
2381 /* Set CFC-11 volume mixing ratio... */
2382 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2383 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2384
2385 /* Set CFC-12 volume mixing ratio... */
2386 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2387 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2388
2389 /* Set N2O volume mixing ratio... */
2390 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2391 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2392
2393 /* Set SF6 volume mixing ratio... */
2394 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2395 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2396
2397 /* Set age of air... */
2398 if (ctl->qnt_aoa >= 0)
2399 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2400 }
2401}
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:383
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:724
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1802
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:707
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3373
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3379
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3367
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3370
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3376
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2452
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2200
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2461
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2796
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2745
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2446
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2718
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2203
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2733
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2751
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2739
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2724
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2730
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2727
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2455
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2449
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2458
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2742
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2721
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2736
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2787
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2799
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2790
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2793
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2748
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 
)

Calculate grid data for chemistry modules.

This function initializes and updates chemical grid quantities based on atmospheric data and interpolation of meteorological variables.

Parameters
ctlPointer to the control structure containing simulation parameters.
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.
tTime for which chemical grid is updated.
Authors
Mingzhao Liu
Lars Hoffmann

Definition at line 2405 of file mptrac.c.

2410 {
2411
2412 /* Check quantities... */
2413 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
2414 return;
2415 if (ctl->molmass <= 0)
2416 ERRMSG("Molar mass is not defined!");
2417
2418 /* Set timer... */
2419 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS", NVTX_GPU);
2420
2421 /* Allocate... */
2422 const int np = atm->np;
2423 const int nz = ctl->chemgrid_nz;
2424 const int nx = ctl->chemgrid_nx;
2425 const int ny = ctl->chemgrid_ny;
2426 const int ngrid = nx * ny * nz;
2427
2428 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2429 double *restrict const press =
2430 (double *) malloc((size_t) nz * sizeof(double));
2431 double *restrict const mass =
2432 (double *) calloc((size_t) ngrid, sizeof(double));
2433 double *restrict const area =
2434 (double *) malloc((size_t) ny * sizeof(double));
2435 double *restrict const lon =
2436 (double *) malloc((size_t) nx * sizeof(double));
2437 double *restrict const lat =
2438 (double *) malloc((size_t) ny * sizeof(double));
2439
2440 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2441 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2442 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2443
2444 /* Set grid box size... */
2445 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2446 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2447 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2448
2449 /* Set vertical coordinates... */
2450#ifdef _OPENACC
2451#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np],z[0:nz],press[0:nz],mass[0:ngrid],area[0:ny],lon[0:nx],lat[0:ny])
2452#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2453#pragma acc parallel loop independent gang vector
2454#else
2455#pragma omp parallel for default(shared)
2456#endif
2457 for (int iz = 0; iz < nz; iz++) {
2458 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2459 press[iz] = P(z[iz]);
2460 }
2461
2462 /* Set time interval for output... */
2463 const double t0 = tt - 0.5 * ctl->dt_mod;
2464 const double t1 = tt + 0.5 * ctl->dt_mod;
2465
2466 /* Get indices... */
2467#ifdef _OPENACC
2468#pragma acc parallel loop independent gang vector
2469#else
2470#pragma omp parallel for default(shared)
2471#endif
2472 for (int ip = 0; ip < np; ip++) {
2473 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2474 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2475 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2476 if (atm->time[ip] < t0 || atm->time[ip] > t1
2477 || ixs[ip] < 0 || ixs[ip] >= nx
2478 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2479 izs[ip] = -1;
2480 }
2481
2482 /* Set horizontal coordinates... */
2483#ifdef _OPENACC
2484#pragma acc parallel loop independent gang vector
2485#else
2486#pragma omp parallel for default(shared)
2487#endif
2488 for (int ix = 0; ix < nx; ix++)
2489 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
2490#ifdef _OPENACC
2491#pragma acc parallel loop independent gang vector
2492#else
2493#pragma omp parallel for default(shared)
2494#endif
2495 for (int iy = 0; iy < ny; iy++) {
2496 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
2497 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
2498 }
2499
2500 /* Get mass per grid box... */
2501#ifdef _OPENACC
2502#pragma acc parallel loop independent gang vector
2503#endif
2504 for (int ip = 0; ip < np; ip++)
2505 if (izs[ip] >= 0)
2506#ifdef _OPENACC
2507#pragma acc atomic update
2508#endif
2509 mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)]
2510 += atm->q[ctl->qnt_m][ip];
2511
2512 /* Assign grid data to air parcels ... */
2513#ifdef _OPENACC
2514#pragma acc parallel loop independent gang vector
2515#else
2516#pragma omp parallel for default(shared)
2517#endif
2518 for (int ip = 0; ip < np; ip++)
2519 if (izs[ip] >= 0) {
2520
2521 /* Interpolate temperature... */
2522 double temp;
2524 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt, press[izs[ip]],
2525 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
2526
2527 /* Set mass... */
2528 const double m = mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)];
2529
2530 /* Calculate volume mixing ratio... */
2531 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
2532 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
2533 }
2534#ifdef _OPENACC
2535#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
2536#endif
2537
2538 /* Free... */
2539 free(mass);
2540 free(lon);
2541 free(lat);
2542 free(area);
2543 free(z);
2544 free(press);
2545 free(ixs);
2546 free(iys);
2547 free(izs);
2548}
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:402
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:208
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1315
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1492
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2757
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2844
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2841
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2859
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2862
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2850
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2853
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2473
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2838
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2847
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2856
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2416
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.
Authors
Mingzhao Liu

Definition at line 2552 of file mptrac.c.

2558 {
2559
2560 /* Set timer... */
2561 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS", NVTX_GPU);
2562
2563 /* Loop over particles... */
2564 PARTICLE_LOOP(0, atm->np, 0,
2565 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2566
2567 /* Set H2O and O3 using meteo data... */
2569 if (ctl->qnt_Ch2o >= 0) {
2570 double h2o;
2571 INTPOL_3D(h2o, 1);
2572 SET_ATM(qnt_Ch2o, h2o);
2573 }
2574 if (ctl->qnt_Co3 >= 0) {
2575 double o3;
2576 INTPOL_3D(o3, 1);
2577 SET_ATM(qnt_Co3, o3);
2578 }
2579
2580 /* Set radical species... */
2581 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
2582 atm->lon[ip], atm->lat[ip], atm->p[ip]));
2583 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
2584 atm->lat[ip], atm->p[ip]));
2585 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
2586 atm->lat[ip], atm->p[ip]));
2587 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
2588 atm->lat[ip], atm->p[ip]));
2589 }
2590}
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:1511
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3361
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3364
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3358
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2419
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2422
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 2594 of file mptrac.c.

2599 {
2600
2601 /* Set timer... */
2602 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
2603
2604 /* Create random numbers... */
2605 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
2606
2607 /* Loop over particles... */
2608 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2609
2610 /* Interpolate CAPE... */
2611 double ps;
2613 INTPOL_2D(ps, 1);
2614
2615 /* Initialize pressure range for vertical mixing... */
2616 double pbot = ps, ptop = ps;
2617
2618 /* Mixing in the PBL... */
2619 if (ctl->conv_mix_pbl) {
2620
2621 /* Interpolate PBL... */
2622 double pbl;
2623 INTPOL_2D(pbl, 0);
2624
2625 /* Set pressure range... */
2626 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
2627 }
2628
2629 /* Convective mixing... */
2630 if (ctl->conv_cape >= 0) {
2631
2632 /* Interpolate CAPE, CIN, and equilibrium level... */
2633 double cape, cin, pel;
2634 INTPOL_2D(cape, 0);
2635 INTPOL_2D(cin, 0);
2636 INTPOL_2D(pel, 0);
2637
2638 /* Set pressure range... */
2639 if (isfinite(cape) && cape >= ctl->conv_cape
2640 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
2641 ptop = GSL_MIN(ptop, pel);
2642 }
2643
2644 /* Apply vertical mixing... */
2645 if (ptop != pbot && atm->p[ip] >= ptop) {
2646
2647 /* Get density range... */
2648 double tbot, ttop;
2649 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2650 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
2651 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2652 ptop, atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
2653 const double rhobot = pbot / tbot;
2654 const double rhotop = ptop / ttop;
2655
2656 /* Get new density... */
2657 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
2658
2659 /* Get pressure... */
2660 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
2661 }
2662 }
2663}
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:3735
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3209
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2709
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2706
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2703
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2712
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 2667 of file mptrac.c.

2671 {
2672
2673 /* Set timer... */
2674 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
2675
2676 /* Check quantity flags... */
2677 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2678 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2679
2680 /* Loop over particles... */
2681 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
2682
2683 /* Get weighting factor... */
2684 const double w = tropo_weight(clim, atm, ip);
2685
2686 /* Set lifetime... */
2687 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
2688
2689 /* Calculate exponential decay... */
2690 const double aux = exp(-cache->dt[ip] / tdec);
2691 if (ctl->qnt_m >= 0) {
2692 if (ctl->qnt_mloss_decay >= 0)
2693 atm->q[ctl->qnt_mloss_decay][ip]
2694 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2695 atm->q[ctl->qnt_m][ip] *= aux;
2696 if (ctl->qnt_loss_rate >= 0)
2697 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
2698 }
2699 if (ctl->qnt_vmr >= 0)
2700 atm->q[ctl->qnt_vmr][ip] *= aux;
2701 }
2702}
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:9337
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2359
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2356
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2763
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2760
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 2706 of file mptrac.c.

2711 {
2712
2713 /* Set timer... */
2714 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS", NVTX_GPU);
2715
2716 /* Create random numbers... */
2717 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2718
2719 /* Loop over particles... */
2720 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2721
2722 /* Get indices... */
2723 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
2724 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
2725 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
2726
2727 /* Get standard deviations of local wind data... */
2728 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
2729 for (int i = 0; i < 2; i++)
2730 for (int j = 0; j < 2; j++)
2731 for (int k = 0; k < 2; k++) {
2732 umean += met0->u[ix + i][iy + j][iz + k];
2733 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
2734 vmean += met0->v[ix + i][iy + j][iz + k];
2735 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
2736 wmean += met0->w[ix + i][iy + j][iz + k];
2737 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
2738
2739 umean += met1->u[ix + i][iy + j][iz + k];
2740 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
2741 vmean += met1->v[ix + i][iy + j][iz + k];
2742 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
2743 wmean += met1->w[ix + i][iy + j][iz + k];
2744 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
2745 }
2746 usig = usig / 16.f - SQR(umean / 16.f);
2747 usig = (usig > 0 ? sqrtf(usig) : 0);
2748 vsig = vsig / 16.f - SQR(vmean / 16.f);
2749 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
2750 wsig = wsig / 16.f - SQR(wmean / 16.f);
2751 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
2752
2753 /* Set temporal correlations for mesoscale fluctuations... */
2754 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
2755 const double r2 = sqrt(1 - r * r);
2756
2757 /* Calculate horizontal mesoscale wind fluctuations... */
2758 if (ctl->turb_mesox > 0) {
2759 cache->uvwp[ip][0] =
2760 (float) (r * cache->uvwp[ip][0] +
2761 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
2762 atm->lon[ip] +=
2763 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2764
2765 cache->uvwp[ip][1] =
2766 (float) (r * cache->uvwp[ip][1] +
2767 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
2768 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2769 }
2770
2771 /* Calculate vertical mesoscale wind fluctuations... */
2772 if (ctl->turb_mesoz > 0) {
2773 cache->uvwp[ip][2] =
2774 (float) (r * cache->uvwp[ip][2] +
2775 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
2776 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
2777 }
2778 }
2779}
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3206
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2700
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2483
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2697
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 2783 of file mptrac.c.

2788 {
2789
2790 /* Set timer... */
2791 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS", NVTX_GPU);
2792
2793 /* Create random numbers... */
2794 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2795
2796 /* Loop over particles... */
2797 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2798
2799 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
2800 tau_u = 300., tau_w = 100.;
2801
2802 /* Get surface and PBL pressure... */
2803 double pbl, ps;
2805 INTPOL_2D(ps, 1);
2806 INTPOL_2D(pbl, 0);
2807
2808 /* Boundary layer... */
2809 if (atm->p[ip] >= pbl) {
2810
2811 /* Calculate heights... */
2812 const double p = MIN(atm->p[ip], ps);
2813 const double zs = Z(ps);
2814 const double z = 1e3 * (Z(p) - zs);
2815 const double zi = 1e3 * (Z(pbl) - zs);
2816 const double zratio = z / zi;
2817
2818 /* Calculate friction velocity... */
2819 double ess, nss, h2o, t;
2820 INTPOL_2D(ess, 0);
2821 INTPOL_2D(nss, 0);
2822 INTPOL_3D(t, 1);
2823 INTPOL_3D(h2o, 0);
2824 const double rho = RHO(p, TVIRT(t, h2o));
2825 const double tau = sqrt(SQR(ess) + SQR(nss));
2826 const double ustar = sqrt(tau / rho);
2827
2828 /* Get surface sensible heat flux... */
2829 double shf;
2830 INTPOL_2D(shf, 1);
2831
2832 /* Stable or neutral conditions... */
2833 if (shf <= 0) {
2834
2835 /* Calcalute turbulent velocity variances... */
2836 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
2837 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
2838
2839 /* Calculate derivative dsig_w/dz... */
2840 dsigw_dz = -1.3 * ustar / zi;
2841
2842 /* Calcalute Lagrangian timescales... */
2843 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
2844 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
2845 }
2846
2847 /* Unstable conditions... */
2848 else {
2849
2850 /* Convective velocity... */
2851 const double wstar =
2852 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
2853
2854 /* Calcalute turbulent velocity variances... */
2855 sig_u = 1e-2
2856 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
2857 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
2858 * pow(zratio, 2.0 / 3.0)
2859 + (1.8 - 1.4 * zratio) * SQR(ustar));
2860
2861 /* Calculate derivative dsig_w/dz... */
2862 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
2863 * (0.8 *
2864 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
2865 - 1.8 * pow(zratio, 2.0 / 3.0)));
2866
2867 /* Calcalute Lagrangian timescales... */
2868 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
2869 const double eps =
2870 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
2871 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
2872 tau_u = 2 * SQR(sig_u) / (C0 * eps);
2873 tau_w = 2 * SQR(sig_w) / (C0 * eps);
2874 }
2875 }
2876
2877 /* Set minimum values... */
2878 sig_u = MAX(sig_u, 0.25);
2879 sig_w = MAX(sig_w, 0.1);
2880 tau_u = MAX(tau_u, 300.);
2881 tau_w = MAX(tau_w, 100.);
2882
2883 /* Update perturbations... */
2884 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
2885 const double ru2 = sqrt(1.0 - SQR(ru));
2886 cache->uvwp[ip][0]
2887 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
2888 cache->uvwp[ip][1]
2889 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
2890
2891 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
2892 const double rw2 = sqrt(1.0 - SQR(rw));
2893 cache->uvwp[ip][2]
2894 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
2895 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
2896
2897 /* Calculate new air parcel position... */
2898 atm->lon[ip] +=
2899 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2900 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2901 atm->p[ip] +=
2902 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
2903 }
2904}
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1730
#define KARMAN
Karman's constant.
Definition: mptrac.h:198
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1684
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:573
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 2908 of file mptrac.c.

2914 {
2915
2916 /* Set timer... */
2917 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS", NVTX_GPU);
2918
2919 /* Create random numbers... */
2920 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2921
2922 /* Loop over particles... */
2923 PARTICLE_LOOP(0, atm->np, 1,
2924 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2925
2926 /* Get PBL and surface pressure... */
2927 double pbl, ps;
2929 INTPOL_2D(pbl, 1);
2930 INTPOL_2D(ps, 0);
2931
2932 /* Get weighting factors... */
2933 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
2934 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
2935 const double wstrat = 1.0 - wpbl - wtrop;
2936
2937 /* Set diffusivity... */
2938 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
2939 + wstrat * ctl->turb_dx_strat;
2940 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
2941 + wstrat * ctl->turb_dz_strat;
2942
2943 /* Horizontal turbulent diffusion... */
2944 if (dx > 0) {
2945 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
2946 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
2947 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
2948 }
2949
2950 /* Vertical turbulent diffusion... */
2951 if (dz > 0) {
2952 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
2953 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
2954 }
2955 }
2956}
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:5937
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2691
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2685
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2682
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2679
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2694
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2688
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 2960 of file mptrac.c.

2965 {
2966
2967 /* Set timer... */
2968 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS", NVTX_GPU);
2969
2970 /* Check quantity flags... */
2971 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2972 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2973
2974 /* Loop over particles... */
2975 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2976
2977 /* Get surface pressure... */
2978 double ps;
2980 INTPOL_2D(ps, 1);
2981
2982 /* Check whether particle is above the surface layer... */
2983 if (atm->p[ip] < ps - ctl->dry_depo_dp)
2984 continue;
2985
2986 /* Set depth of surface layer... */
2987 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
2988
2989 /* Calculate sedimentation velocity for particles... */
2990 double v_dep;
2991 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
2992
2993 /* Get temperature... */
2994 double t;
2995 INTPOL_3D(t, 1);
2996
2997 /* Set deposition velocity... */
2998 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
2999 atm->q[ctl->qnt_rhop][ip]);
3000 }
3001
3002 /* Use explicit sedimentation velocity for gases... */
3003 else
3004 v_dep = ctl->dry_depo_vdep;
3005
3006 /* Calculate loss of mass based on deposition velocity... */
3007 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3008 if (ctl->qnt_m >= 0) {
3009 if (ctl->qnt_mloss_dry >= 0)
3010 atm->q[ctl->qnt_mloss_dry][ip]
3011 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3012 atm->q[ctl->qnt_m][ip] *= aux;
3013 if (ctl->qnt_loss_rate >= 0)
3014 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3015 }
3016 if (ctl->qnt_vmr >= 0)
3017 atm->q[ctl->qnt_vmr][ip] *= aux;
3018 }
3019}
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:9061
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2209
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2206
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2916
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2353
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2919
Here is the call graph for this function:

◆ module_h2o2_chem()

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

Perform chemical reactions involving H2O2 within cloud particles.

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

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

Definition at line 3023 of file mptrac.c.

3029 {
3030
3031 /* Set timer... */
3032 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS", NVTX_GPU);
3033
3034 /* Check quantity flags... */
3035 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3036 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3037
3038 /* Parameter of SO2 correction... */
3039 const double a = 3.12541941e-06;
3040 const double b = -5.72532259e-01;
3041 const double low = pow(1. / a, 1. / b);
3042
3043 /* Loop over particles... */
3044 PARTICLE_LOOP(0, atm->np, 1,
3045 "acc data present(ctl,cache,ctl,met0,met1,atm)") {
3046
3047 /* Check whether particle is inside cloud... */
3048 double lwc, rwc;
3050 INTPOL_3D(lwc, 1);
3051 INTPOL_3D(rwc, 0);
3052 if (!(lwc > 0 || rwc > 0))
3053 continue;
3054
3055 /* Get temperature... */
3056 double t;
3057 INTPOL_3D(t, 0);
3058
3059 /* Get molecular density... */
3060 const double M = MOLEC_DENS(atm->p[ip], t);
3061
3062 /* Reaction rate (Berglen et al., 2004)... */
3063 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3064
3065 /* Henry constant of SO2... */
3066 const double H_SO2 =
3067 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3068 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3069
3070 /* Henry constant of H2O2... */
3071 const double H_h2o2 =
3072 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3073
3074 /* Correction factor for high SO2 concentration
3075 (if qnt_Cx is defined, the correction is switched on)... */
3076 double cor = 1.0;
3077 if (ctl->qnt_Cx >= 0)
3078 cor = atm->q[ctl->qnt_Cx][ip] >
3079 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3080
3081 const double h2o2 = H_h2o2
3082 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3083 * M * cor * 1000. / AVO; /* unit: mol/L */
3084
3085 /* Volume water content in cloud [m^3 m^(-3)]... */
3086 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3087 const double CWC = (lwc + rwc) * rho_air / 1e3;
3088
3089 /* Calculate exponential decay (Rolph et al., 1992)... */
3090 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3091 const double aux = exp(-cache->dt[ip] * rate_coef);
3092 if (ctl->qnt_m >= 0) {
3093 if (ctl->qnt_mloss_h2o2 >= 0)
3094 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3095 atm->q[ctl->qnt_m][ip] *= aux;
3096 if (ctl->qnt_loss_rate >= 0)
3097 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3098 }
3099 if (ctl->qnt_vmr >= 0)
3100 atm->q[ctl->qnt_vmr][ip] *= aux;
3101 }
3102}
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:168
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1013
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:238
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2344
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 3106 of file mptrac.c.

3111 {
3112
3113 double t;
3114
3115 /* Set timer... */
3116 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS", NVTX_GPU);
3117
3118 /* Save pressure... */
3119 if (ctl->isosurf == 1) {
3120 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3121 cache->iso_var[ip] = atm->p[ip];
3122 }
3123 }
3124
3125 /* Save density... */
3126 else if (ctl->isosurf == 2) {
3127 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3129 INTPOL_3D(t, 1);
3130 cache->iso_var[ip] = atm->p[ip] / t;
3131 }
3132 }
3133
3134 /* Save potential temperature... */
3135 else if (ctl->isosurf == 3) {
3136 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3138 INTPOL_3D(t, 1);
3139 cache->iso_var[ip] = THETA(atm->p[ip], t);
3140 }
3141 }
3142
3143 /* Read balloon pressure data... */
3144 else if (ctl->isosurf == 4) {
3145
3146 /* Write info... */
3147 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3148
3149 /* Open file... */
3150 FILE *in;
3151 if (!(in = fopen(ctl->balloon, "r")))
3152 ERRMSG("Cannot open file!");
3153
3154 /* Read pressure time series... */
3155 char line[LEN];
3156 while (fgets(line, LEN, in))
3157 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3158 &(cache->iso_ps[cache->iso_n])) == 2)
3159 if ((++cache->iso_n) > NP)
3160 ERRMSG("Too many data points!");
3161
3162 /* Check number of points... */
3163 if (cache->iso_n < 1)
3164 ERRMSG("Could not read any data!");
3165
3166 /* Close file... */
3167 fclose(in);
3168
3169 /* Update of cache data on device... */
3170 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
3171 }
3172}
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:5610
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1655
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3200
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3203
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3197
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3194
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2663
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2660
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 3176 of file mptrac.c.

3181 {
3182
3183 /* Set timer... */
3184 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3185
3186 /* Loop over particles... */
3187 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
3188
3189 /* Init... */
3190 double t;
3192
3193 /* Restore pressure... */
3194 if (ctl->isosurf == 1)
3195 atm->p[ip] = cache->iso_var[ip];
3196
3197 /* Restore density... */
3198 else if (ctl->isosurf == 2) {
3199 INTPOL_3D(t, 1);
3200 atm->p[ip] = cache->iso_var[ip] * t;
3201 }
3202
3203 /* Restore potential temperature... */
3204 else if (ctl->isosurf == 3) {
3205 INTPOL_3D(t, 1);
3206 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3207 }
3208
3209 /* Interpolate pressure... */
3210 else if (ctl->isosurf == 4) {
3211 if (atm->time[ip] <= cache->iso_ts[0])
3212 atm->p[ip] = cache->iso_ps[0];
3213 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3214 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3215 else {
3216 int idx = locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3217 atm->p[ip] = LIN(cache->iso_ts[idx], cache->iso_ps[idx],
3218 cache->iso_ts[idx + 1], cache->iso_ps[idx + 1],
3219 atm->time[ip]);
3220 }
3221 }
3222 }
3223}
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 3281 of file mptrac.c.

3287 {
3288
3289 /* Set timer... */
3290 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
3291
3292 /* Check quantity flags... */
3293 if (ctl->qnt_tsts >= 0)
3294 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3295 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3296
3297 /* Loop over particles... */
3298 PARTICLE_LOOP(0, atm->np, 0,
3299 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3300
3301 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb, cl,
3302 plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot, o3, lwc,
3303 rwc, iwc, swc, cc, z, zt;
3304
3305 /* Interpolate meteo data... */
3307 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3308
3309 /* Set quantities... */
3310 SET_ATM(qnt_ps, ps);
3311 SET_ATM(qnt_ts, ts);
3312 SET_ATM(qnt_zs, zs);
3313 SET_ATM(qnt_us, us);
3314 SET_ATM(qnt_vs, vs);
3315 SET_ATM(qnt_ess, ess);
3316 SET_ATM(qnt_nss, nss);
3317 SET_ATM(qnt_shf, shf);
3318 SET_ATM(qnt_lsm, lsm);
3319 SET_ATM(qnt_sst, sst);
3320 SET_ATM(qnt_pbl, pbl);
3321 SET_ATM(qnt_pt, pt);
3322 SET_ATM(qnt_tt, tt);
3323 SET_ATM(qnt_zt, zt);
3324 SET_ATM(qnt_h2ot, h2ot);
3325 SET_ATM(qnt_zg, z);
3326 SET_ATM(qnt_p, atm->p[ip]);
3327 SET_ATM(qnt_t, t);
3328 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3329 SET_ATM(qnt_u, u);
3330 SET_ATM(qnt_v, v);
3331 SET_ATM(qnt_w, w);
3332 SET_ATM(qnt_h2o, h2o);
3333 SET_ATM(qnt_o3, o3);
3334 SET_ATM(qnt_lwc, lwc);
3335 SET_ATM(qnt_rwc, rwc);
3336 SET_ATM(qnt_iwc, iwc);
3337 SET_ATM(qnt_swc, swc);
3338 SET_ATM(qnt_cc, cc);
3339 SET_ATM(qnt_pct, pct);
3340 SET_ATM(qnt_pcb, pcb);
3341 SET_ATM(qnt_cl, cl);
3342 SET_ATM(qnt_plcl, plcl);
3343 SET_ATM(qnt_plfc, plfc);
3344 SET_ATM(qnt_pel, pel);
3345 SET_ATM(qnt_cape, cape);
3346 SET_ATM(qnt_cin, cin);
3347 SET_ATM(qnt_o3c, o3c);
3348 SET_ATM(qnt_hno3,
3349 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3350 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3351 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3352 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3353 atm->lat[ip], atm->p[ip]));
3354 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3355 atm->lat[ip], atm->p[ip]));
3356 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3357 atm->lat[ip], atm->p[ip]));
3358 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3359 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3360 SET_ATM(qnt_psat, PSAT(t));
3361 SET_ATM(qnt_psice, PSICE(t));
3362 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3363 SET_ATM(qnt_sh, SH(h2o));
3364 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3365 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3366 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3367 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3368 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3369 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3370 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3371 SET_ATM(qnt_pv, pv);
3372 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3373 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3374 SET_ATM(qnt_tnat,
3375 nat_temperature(atm->p[ip], h2o,
3376 clim_zm(&clim->hno3, atm->time[ip],
3377 atm->lat[ip], atm->p[ip])));
3378 SET_ATM(qnt_tsts,
3379 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3380 }
3381}
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:5913
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:1799
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1390
#define H0
Scale height [km].
Definition: mptrac.h:188
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1363
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1631
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1467
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:797
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1437
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1606
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1339
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3352
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2413
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2407
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2410
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.
Authors
Mingzhao Liu
Lars Hoffmann

Definition at line 3385 of file mptrac.c.

3389 {
3390
3391 /* Set timer... */
3392 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
3393
3394 /* Allocate... */
3395 const int np = atm->np;
3396 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3397 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3398 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3399
3400 /* Set grid box size... */
3401 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3402 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3403 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3404
3405 /* Set time interval... */
3406 const double t0 = t - 0.5 * ctl->dt_mod;
3407 const double t1 = t + 0.5 * ctl->dt_mod;
3408
3409 /* Get indices... */
3410#ifdef _OPENACC
3411#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3412#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3413#pragma acc parallel loop independent gang vector
3414#else
3415#pragma omp parallel for default(shared)
3416#endif
3417 for (int ip = 0; ip < np; ip++) {
3418 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3419 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3420 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3421 if (atm->time[ip] < t0 || atm->time[ip] > t1
3422 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3423 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3424 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3425 izs[ip] = -1;
3426 }
3427
3428 /* Calculate interparcel mixing... */
3429 if (ctl->qnt_m >= 0)
3430 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_m);
3431 if (ctl->qnt_vmr >= 0)
3432 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_vmr);
3433 if (ctl->qnt_Ch2o >= 0)
3434 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o);
3435 if (ctl->qnt_Co3 >= 0)
3436 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3);
3437 if (ctl->qnt_Cco >= 0)
3438 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cco);
3439 if (ctl->qnt_Coh >= 0)
3440 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Coh);
3441 if (ctl->qnt_Ch >= 0)
3442 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch);
3443 if (ctl->qnt_Cho2 >= 0)
3444 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cho2);
3445 if (ctl->qnt_Ch2o2 >= 0)
3446 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o2);
3447 if (ctl->qnt_Co1d >= 0)
3448 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co1d);
3449 if (ctl->qnt_Co3p >= 0)
3450 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3p);
3451 if (ctl->qnt_Cccl4 >= 0)
3452 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl4);
3453 if (ctl->qnt_Cccl3f >= 0)
3454 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl3f);
3455 if (ctl->qnt_Cccl2f2 >= 0)
3456 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl2f2);
3457 if (ctl->qnt_Cn2o >= 0)
3458 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cn2o);
3459 if (ctl->qnt_Csf6 >= 0)
3460 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Csf6);
3461 if (ctl->qnt_aoa >= 0)
3462 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_aoa);
3463
3464 /* Free... */
3465#ifdef _OPENACC
3466#pragma acc exit data delete(ixs,iys,izs)
3467#endif
3468 free(ixs);
3469 free(iys);
3470 free(izs);
3471}
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)
Perform interparcel mixing for a specific quantity.
Definition: mptrac.c:3475
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2428
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2820
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2817
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2440
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2814
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2425
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2829
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2431
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2832
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2434
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2811
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2823
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2835
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2443
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2437
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2826
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 
)

Perform interparcel mixing for a specific quantity.

This function performs interparcel mixing for a specific quantity based on the given indices of grid boxes. It calculates the mean concentration within each grid box and adjusts the quantity for each particle accordingly.

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.
ixsPointer to the array of grid box indices along the longitude direction.
iysPointer to the array of grid box indices along the latitude direction.
izsPointer to the array of grid box indices along the vertical direction.
qnt_idxIndex of the quantity for which mixing is performed.
Authors
Mingzhao Liu
Lars Hoffmann

Definition at line 3475 of file mptrac.c.

3482 {
3483
3484 /* Allocate... */
3485 const int np = atm->np;
3486 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
3487 double *restrict const cmean =
3488 (double *) malloc((size_t) ngrid * sizeof(double));
3489 int *restrict const count = (int *) malloc((size_t) ngrid * sizeof(int));
3490
3491 /* Init... */
3492#ifdef _OPENACC
3493#pragma acc enter data create(cmean[0:ngrid],count[0:ngrid])
3494#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
3495#pragma acc parallel loop independent gang vector
3496#else
3497#ifdef __NVCOMPILER
3498#pragma novector
3499#endif
3500#pragma omp parallel for
3501#endif
3502 for (int i = 0; i < ngrid; i++) {
3503 count[i] = 0;
3504 cmean[i] = 0;
3505 }
3506
3507 /* Loop over particles... */
3508#ifdef _OPENACC
3509#pragma acc parallel loop independent gang vector
3510#endif
3511 for (int ip = 0; ip < np; ip++)
3512 if (izs[ip] >= 0) {
3513 int idx = ARRAY_3D
3514 (ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz);
3515#ifdef _OPENACC
3516#pragma acc atomic update
3517#endif
3518 cmean[idx] += atm->q[qnt_idx][ip];
3519#ifdef _OPENACC
3520#pragma acc atomic update
3521#endif
3522 count[idx]++;
3523 }
3524#ifdef _OPENACC
3525#pragma acc parallel loop independent gang vector
3526#else
3527#ifdef __NVCOMPILER
3528#pragma novector
3529#endif
3530#pragma omp parallel for
3531#endif
3532 for (int i = 0; i < ngrid; i++)
3533 if (count[i] > 0)
3534 cmean[i] /= count[i];
3535
3536 /* Calculate interparcel mixing... */
3537#ifdef _OPENACC
3538#pragma acc parallel loop independent gang vector
3539#else
3540#pragma omp parallel for
3541#endif
3542 for (int ip = 0; ip < np; ip++)
3543 if (izs[ip] >= 0) {
3544
3545 /* Set mixing parameter... */
3546 double mixparam = 1.0;
3547 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
3548 double w = tropo_weight(clim, atm, ip);
3549 mixparam = w * ctl->mixing_trop + (1 - w) * ctl->mixing_strat;
3550 }
3551
3552 /* Adjust quantity... */
3553 atm->q[qnt_idx][ip] +=
3554 (cmean
3555 [ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz)]
3556 - atm->q[qnt_idx][ip]) * mixparam;
3557 }
3558
3559 /* Free... */
3560#ifdef _OPENACC
3561#pragma acc exit data delete(cmean,count)
3562#endif
3563 free(cmean);
3564 free(count);
3565}
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2805
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2808
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).
Authors
Lars Hoffmann
Mingzhao Liu

Definition at line 3569 of file mptrac.c.

3575 {
3576
3577 /* Set timer... */
3578 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS", NVTX_GPU);
3579
3580 /* Check quantity flags... */
3581 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3582 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3583
3584 /* Parameter of SO2 correction... */
3585 const double a = 4.71572206e-08;
3586 const double b = -8.28782867e-01;
3587 const double low = pow(1. / a, 1. / b);
3588
3589 /* Loop over particles... */
3590 PARTICLE_LOOP(0, atm->np, 1,
3591 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3592
3593 /* Get temperature... */
3594 double t;
3596 INTPOL_3D(t, 1);
3597
3598 /* Calculate molecular density... */
3599 const double M = MOLEC_DENS(atm->p[ip], t);
3600
3601 /* Use constant reaction rate... */
3602 double k = NAN;
3603 if (ctl->oh_chem_reaction == 1)
3604 k = ctl->oh_chem[0];
3605
3606 /* Calculate bimolecular reaction rate... */
3607 else if (ctl->oh_chem_reaction == 2)
3608 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
3609
3610 /* Calculate termolecular reaction rate... */
3611 if (ctl->oh_chem_reaction == 3) {
3612
3613 /* Calculate rate coefficient for X + OH + M -> XOH + M
3614 (JPL Publication 19-05) ... */
3615 const double k0 =
3616 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
3617 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
3618 const double ki =
3619 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
3620 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
3621 const double c = log10(k0 * M / ki);
3622 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
3623 }
3624
3625 /* Correction factor for high SO2 concentration
3626 (if qnt_Cx is defined, the correction is switched on)... */
3627 double cor = 1;
3628 if (ctl->qnt_Cx >= 0)
3629 cor =
3630 atm->q[ctl->qnt_Cx][ip] >
3631 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3632
3633 /* Calculate exponential decay... */
3634 const double rate_coef =
3635 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
3636 atm->lat[ip], atm->p[ip]) * M * cor;
3637 const double aux = exp(-cache->dt[ip] * rate_coef);
3638 if (ctl->qnt_m >= 0) {
3639 if (ctl->qnt_mloss_oh >= 0)
3640 atm->q[ctl->qnt_mloss_oh][ip]
3641 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3642 atm->q[ctl->qnt_m][ip] *= aux;
3643 if (ctl->qnt_loss_rate >= 0)
3644 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3645 }
3646 if (ctl->qnt_vmr >= 0)
3647 atm->q[ctl->qnt_vmr][ip] *= aux;
3648 }
3649}
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2868
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2865
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2341
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 3653 of file mptrac.c.

3657 {
3658
3659 /* Set timer... */
3660 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
3661
3662 /* Loop over particles... */
3663 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
3664
3665 /* Init... */
3666 double ps;
3668
3669 /* Calculate modulo... */
3670 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
3671 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
3672
3673 /* Check latitude... */
3674 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
3675 if (atm->lat[ip] > 90) {
3676 atm->lat[ip] = 180 - atm->lat[ip];
3677 atm->lon[ip] += 180;
3678 }
3679 if (atm->lat[ip] < -90) {
3680 atm->lat[ip] = -180 - atm->lat[ip];
3681 atm->lon[ip] += 180;
3682 }
3683 }
3684
3685 /* Check longitude... */
3686 while (atm->lon[ip] < -180)
3687 atm->lon[ip] += 360;
3688 while (atm->lon[ip] >= 180)
3689 atm->lon[ip] -= 360;
3690
3691 /* Check pressure... */
3692 if (atm->p[ip] < met0->p[met0->np - 1]) {
3693 atm->p[ip] = met0->p[met0->np - 1];
3694 } else if (atm->p[ip] > 300.) {
3695 INTPOL_2D(ps, 1);
3696 if (atm->p[ip] > ps)
3697 atm->p[ip] = ps;
3698 }
3699 }
3700}

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

3705 {
3706
3707 /* Initialize GSL random number generators... */
3708 gsl_rng_env_setup();
3709 if (omp_get_max_threads() > NTHREADS)
3710 ERRMSG("Too many threads!");
3711 for (int i = 0; i < NTHREADS; i++) {
3712 rng[i] = gsl_rng_alloc(gsl_rng_default);
3713 gsl_rng_set(rng[i], gsl_rng_default_seed
3714 + (long unsigned) (ntask * NTHREADS + i));
3715 }
3716
3717 /* Initialize cuRAND random number generators... */
3718#ifdef CURAND
3719 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
3720 CURAND_STATUS_SUCCESS)
3721 ERRMSG("Cannot create random number generator!");
3722 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
3723 CURAND_STATUS_SUCCESS)
3724 ERRMSG("Cannot set seed for random number generator!");
3725 if (curandSetStream
3726 (rng_curand,
3727 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
3728 CURAND_STATUS_SUCCESS)
3729 ERRMSG("Cannot set stream for random number generator!");
3730#endif
3731}
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:297

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

3739 {
3740
3741 /* Use GSL random number generators... */
3742 if (ctl->rng_type == 0) {
3743
3744 /* Uniform distribution... */
3745 if (method == 0) {
3746#pragma omp parallel for default(shared)
3747 for (size_t i = 0; i < n; ++i)
3748 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
3749 }
3750
3751 /* Normal distribution... */
3752 else if (method == 1) {
3753#pragma omp parallel for default(shared)
3754 for (size_t i = 0; i < n; ++i)
3755 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
3756 }
3757
3758 /* Update of random numbers on device... */
3759#ifdef _OPENACC
3760 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
3761#pragma acc update device(rs[:n])
3762#endif
3763 }
3764
3765 /* Use Squares random number generator (Widynski, 2022)... */
3766 else if (ctl->rng_type == 1) {
3767
3768 /* Set key (don't change this!)... */
3769 const uint64_t key = 0xc8e4fd154ce32f6d;
3770
3771 /* Uniform distribution... */
3772#ifdef _OPENACC
3773#pragma acc data present(rs)
3774#pragma acc parallel loop independent gang vector
3775#else
3776#pragma omp parallel for default(shared)
3777#endif
3778 for (size_t i = 0; i < n + 1; ++i) {
3779 uint64_t r, t, x, y, z;
3780 y = x = (rng_ctr + i) * key;
3781 z = y + key;
3782 x = x * x + y;
3783 x = (x >> 32) | (x << 32);
3784 x = x * x + z;
3785 x = (x >> 32) | (x << 32);
3786 x = x * x + y;
3787 x = (x >> 32) | (x << 32);
3788 t = x = x * x + z;
3789 x = (x >> 32) | (x << 32);
3790 r = t ^ ((x * x + y) >> 32);
3791 rs[i] = (double) r / (double) UINT64_MAX;
3792 }
3793 rng_ctr += n + 1;
3794
3795 /* Normal distribution... */
3796 if (method == 1) {
3797#ifdef _OPENACC
3798#pragma acc parallel loop independent gang vector
3799#else
3800#pragma omp parallel for default(shared)
3801#endif
3802 for (size_t i = 0; i < n; i += 2) {
3803 const double r = sqrt(-2.0 * log(rs[i]));
3804 const double phi = 2.0 * M_PI * rs[i + 1];
3805 rs[i] = r * cosf((float) phi);
3806 rs[i + 1] = r * sinf((float) phi);
3807 }
3808 }
3809 }
3810
3811 /* Use cuRAND random number generators... */
3812 else if (ctl->rng_type == 2) {
3813#ifdef CURAND
3814#pragma acc host_data use_device(rs)
3815 {
3816
3817 /* Uniform distribution... */
3818 if (method == 0) {
3819 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
3820 CURAND_STATUS_SUCCESS)
3821 ERRMSG("Cannot create random numbers!");
3822 }
3823
3824 /* Normal distribution... */
3825 else if (method == 1) {
3826 if (curandGenerateNormalDouble
3827 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
3828 1.0) != CURAND_STATUS_SUCCESS)
3829 ERRMSG("Cannot create random numbers!");
3830 }
3831 }
3832#else
3833 ERRMSG("MPTRAC was compiled without cuRAND!");
3834#endif
3835 }
3836}
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2673

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

3845 {
3846
3847 /* Set timer... */
3848 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
3849
3850 /* Loop over particles... */
3851 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3852
3853 /* Get temperature... */
3854 double t;
3856 INTPOL_3D(t, 1);
3857
3858 /* Sedimentation velocity... */
3859 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3860 atm->q[ctl->qnt_rhop][ip]);
3861
3862 /* Calculate pressure change... */
3863 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
3864 }
3865}
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 3869 of file mptrac.c.

3872 {
3873
3874 /* Set timer... */
3875 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
3876
3877 /* Allocate... */
3878 const int np = atm->np;
3879 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
3880 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
3881
3882#ifdef _OPENACC
3883#pragma acc enter data create(a[0:np],p[0:np])
3884#pragma acc data present(ctl,met0,atm,a,p)
3885#endif
3886
3887 /* Get box index... */
3888#ifdef _OPENACC
3889#pragma acc parallel loop independent gang vector
3890#else
3891#pragma omp parallel for default(shared)
3892#endif
3893 for (int ip = 0; ip < np; ip++) {
3894 a[ip] =
3895 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
3896 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
3897 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
3898 p[ip] = ip;
3899 }
3900
3901 /* Sorting... */
3902#ifdef _OPENACC
3903#pragma acc host_data use_device(a,p)
3904#endif
3905#ifdef THRUST
3906 thrustSortWrapper(a, np, p);
3907#else
3908 ERRMSG("MPTRAC was compiled without Thrust library!");
3909#endif
3910
3911 /* Sort data... */
3912 module_sort_help(atm->time, p, np);
3913 module_sort_help(atm->p, p, np);
3914 module_sort_help(atm->lon, p, np);
3915 module_sort_help(atm->lat, p, np);
3916 for (int iq = 0; iq < ctl->nq; iq++)
3917 module_sort_help(atm->q[iq], p, np);
3918
3919 /* Free... */
3920#ifdef _OPENACC
3921#pragma acc exit data delete(a,p)
3922#endif
3923 free(a);
3924 free(p);
3925}
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:3929
void thrustSortWrapper(double *__restrict__ c, int n, int *__restrict__ index)
Wrapper to Thrust sorting function.
int nq
Number of quantities.
Definition: mptrac.h:2176
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 3929 of file mptrac.c.

3932 {
3933
3934 /* Allocate... */
3935 double *restrict const help =
3936 (double *) malloc((size_t) np * sizeof(double));
3937
3938 /* Reordering of array... */
3939#ifdef _OPENACC
3940#pragma acc enter data create(help[0:np])
3941#pragma acc data present(a,p,help)
3942#pragma acc parallel loop independent gang vector
3943#else
3944#pragma omp parallel for default(shared)
3945#endif
3946 for (int ip = 0; ip < np; ip++)
3947 help[ip] = a[p[ip]];
3948#ifdef _OPENACC
3949#pragma acc parallel loop independent gang vector
3950#else
3951#pragma omp parallel for default(shared)
3952#endif
3953 for (int ip = 0; ip < np; ip++)
3954 a[ip] = help[ip];
3955
3956 /* Free... */
3957#ifdef _OPENACC
3958#pragma acc exit data delete(help)
3959#endif
3960 free(help);
3961}

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

3970 {
3971
3972 /* Set timer... */
3973 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3974
3975 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
3976 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
3977
3978 const int local =
3979 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
3980
3981 /* Loop over particles... */
3982 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
3983
3984 /* Set time step for each air parcel... */
3985 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
3986 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
3987 && ctl->direction * (atm->time[ip] - t) < 0))
3988 cache->dt[ip] = t - atm->time[ip];
3989 else
3990 cache->dt[ip] = 0.0;
3991
3992 /* Check horizontal boundaries of local meteo data... */
3993 if (local && (atm->lon[ip] <= met0->lon[0]
3994 || atm->lon[ip] >= met0->lon[met0->nx - 1]
3995 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
3996 cache->dt[ip] = 0.0;
3997 }
3998}
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2464
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2470
double t_start
Start time of simulation [s].
Definition: mptrac.h:2467

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

4004 {
4005
4006 /* Set timer... */
4007 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS", NVTX_GPU);
4008
4009 /* Set start time... */
4010 if (ctl->direction == 1) {
4011 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4012 if (ctl->t_stop > 1e99)
4013 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4014 } else {
4015 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4016 if (ctl->t_stop > 1e99)
4017 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4018 }
4019
4020 /* Check time interval... */
4021 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4022 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4023
4024 /* Round start time... */
4025 if (ctl->direction == 1)
4026 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4027 else
4028 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4029}

◆ 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.
Authors
Mingzhao Liu
Lars Hoffmann

Definition at line 4033 of file mptrac.c.

4039 {
4040
4041 /* Set timer... */
4042 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS", NVTX_GPU);
4043
4044 /* Loop over particles... */
4045 PARTICLE_LOOP(0, atm->np, 1,
4046 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4047
4048 /* Get temperature... */
4049 double t;
4051 INTPOL_3D(t, 1);
4052
4053 /* Get molecular density... */
4054 const double M = MOLEC_DENS(atm->p[ip], t);
4055
4056 /* Get total column ozone... */
4057 double o3c;
4058 INTPOL_2D(o3c, 1);
4059
4060 /* Get solar zenith angle... */
4061 const double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
4062
4063 /* Get O(1D) volume mixing ratio... */
4064 const double o1d =
4065 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4066
4067 /* Reactions for CFC-10... */
4068 if (ctl->qnt_Cccl4 >= 0) {
4069 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4070 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4071 atm->p[ip], sza, o3c);
4072 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4073 }
4074
4075 /* Reactions for CFC-11... */
4076 if (ctl->qnt_Cccl3f >= 0) {
4077 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4078 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4079 atm->p[ip], sza, o3c);
4080 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4081 }
4082
4083 /* Reactions for CFC-12... */
4084 if (ctl->qnt_Cccl2f2 >= 0) {
4085 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4086 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4087 atm->p[ip], sza, o3c);
4088 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4089 }
4090
4091 /* Reactions for N2O... */
4092 if (ctl->qnt_Cn2o >= 0) {
4093 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4094 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4095 atm->p[ip], sza, o3c);
4096 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4097 }
4098 }
4099}
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:149
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:427
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3253
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3250
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3244
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3247
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3349
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.
Authors
Lars Hoffmann
Mingzhao Liu

Definition at line 4103 of file mptrac.c.

4108 {
4109
4110 /* Set timer... */
4111 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS", NVTX_GPU);
4112
4113 /* Check quantity flags... */
4114 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4115 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4116
4117 /* Loop over particles... */
4118 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4119
4120 /* Check whether particle is below cloud top... */
4121 double pct;
4123 INTPOL_2D(pct, 1);
4124 if (!isfinite(pct) || atm->p[ip] <= pct)
4125 continue;
4126
4127 /* Get cloud bottom pressure... */
4128 double pcb;
4129 INTPOL_2D(pcb, 0);
4130
4131 /* Estimate precipitation rate (Pisso et al., 2019)... */
4132 double cl;
4133 INTPOL_2D(cl, 0);
4134 const double Is =
4135 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4136 if (Is < 0.01)
4137 continue;
4138
4139 /* Check whether particle is inside or below cloud... */
4140 double lwc, rwc, iwc, swc;
4141 INTPOL_3D(lwc, 1);
4142 INTPOL_3D(rwc, 0);
4143 INTPOL_3D(iwc, 0);
4144 INTPOL_3D(swc, 0);
4145 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4146
4147 /* Get temperature... */
4148 double t;
4149 INTPOL_3D(t, 0);
4150
4151 /* Calculate in-cloud scavenging coefficient... */
4152 double lambda = 0;
4153 if (inside) {
4154
4155 /* Calculate retention factor... */
4156 double eta;
4157 if (t > 273.15)
4158 eta = 1;
4159 else if (t <= 238.15)
4160 eta = ctl->wet_depo_ic_ret_ratio;
4161 else
4162 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4163
4164 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4165 if (ctl->wet_depo_ic_a > 0)
4166 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4167
4168 /* Use Henry's law for gases... */
4169 else if (ctl->wet_depo_ic_h[0] > 0) {
4170
4171 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4172 double h = ctl->wet_depo_ic_h[0]
4173 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4174
4175 /* Use effective Henry's constant for SO2
4176 (Berglen, 2004; Simpson, 2012)... */
4177 if (ctl->wet_depo_so2_ph > 0) {
4178 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
4179 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4180 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4181 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
4182 }
4183
4184 /* Estimate depth of cloud layer... */
4185 const double dz = 1e3 * (Z(pct) - Z(pcb));
4186
4187 /* Calculate scavenging coefficient... */
4188 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4189 }
4190 }
4191
4192 /* Calculate below-cloud scavenging coefficient... */
4193 else {
4194
4195 /* Calculate retention factor... */
4196 double eta;
4197 if (t > 270)
4198 eta = 1;
4199 else
4200 eta = ctl->wet_depo_bc_ret_ratio;
4201
4202 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4203 if (ctl->wet_depo_bc_a > 0)
4204 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4205
4206 /* Use Henry's law for gases... */
4207 else if (ctl->wet_depo_bc_h[0] > 0) {
4208
4209 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4210 const double h = ctl->wet_depo_bc_h[0]
4211 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4212
4213 /* Estimate depth of cloud layer... */
4214 const double dz = 1e3 * (Z(pct) - Z(pcb));
4215
4216 /* Calculate scavenging coefficient... */
4217 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4218 }
4219 }
4220
4221 /* Calculate exponential decay of mass... */
4222 const double aux = exp(-cache->dt[ip] * lambda);
4223 if (ctl->qnt_m >= 0) {
4224 if (ctl->qnt_mloss_wet >= 0)
4225 atm->q[ctl->qnt_mloss_wet][ip]
4226 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4227 atm->q[ctl->qnt_m][ip] *= aux;
4228 if (ctl->qnt_loss_rate >= 0)
4229 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4230 }
4231 if (ctl->qnt_vmr >= 0)
4232 atm->q[ctl->qnt_vmr][ip] *= aux;
4233 }
4234}
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2895
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2889
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2350
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2907
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2886
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2904
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2913
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2901
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2910
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2898
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2892

◆ mptrac_alloc()

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

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

4244 {
4245
4246 /* Initialize GPU... */
4247#ifdef _OPENACC
4248 SELECT_TIMER("ACC_INIT", "INIT", NVTX_GPU);
4249 int rank = 0;
4250#ifdef MPI
4251 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
4252#endif
4253 if (acc_get_num_devices(acc_device_nvidia) <= 0)
4254 ERRMSG("Not running on a GPU device!");
4255 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
4256 acc_device_nvidia);
4257 acc_device_t device_type = acc_get_device_type();
4258 acc_init(device_type);
4259#endif
4260
4261 /* Allocate... */
4262 SELECT_TIMER("ALLOC", "MEMORY", NVTX_CPU);
4263 ALLOC(*ctl, ctl_t, 1);
4264 ALLOC(*cache, cache_t, 1);
4265 ALLOC(*clim, clim_t, 1);
4266 ALLOC(*met0, met_t, 1);
4267 ALLOC(*met1, met_t, 1);
4268 ALLOC(*atm, atm_t, 1);
4269
4270 /* Create data region on GPU... */
4271#ifdef _OPENACC
4272 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY", NVTX_GPU);
4273 ctl_t *ctlup = *ctl;
4274 cache_t *cacheup = *cache;
4275 clim_t *climup = *clim;
4276 met_t *met0up = *met0;
4277 met_t *met1up = *met1;
4278 atm_t *atmup = *atm;
4279#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
4280#endif
4281}
Air parcel data.
Definition: mptrac.h:3163
Cache data structure.
Definition: mptrac.h:3191
Climatological data.
Definition: mptrac.h:3331
Control parameters.
Definition: mptrac.h:2169
Meteo data structure.
Definition: mptrac.h:3390

◆ mptrac_free()

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

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

4291 {
4292
4293 /* Delete data region on GPU... */
4294#ifdef _OPENACC
4295 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY", NVTX_GPU);
4296#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
4297#endif
4298
4299 /* Free... */
4300 SELECT_TIMER("FREE", "MEMORY", NVTX_CPU);
4301 free(atm);
4302 free(ctl);
4303 free(cache);
4304 free(clim);
4305 free(met0);
4306 free(met1);
4307}

◆ mptrac_get_met()

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

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

4316 {
4317
4318 static int init;
4319
4320 met_t *mets;
4321
4322 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
4323
4324 /* Set timer... */
4325 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4326
4327 /* Init... */
4328 if (t == ctl->t_start || !init) {
4329 init = 1;
4330
4331 /* Read meteo data... */
4332 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
4333 ctl->metbase, ctl->dt_met, filename);
4334 if (!mptrac_read_met(filename, ctl, clim, *met0))
4335 ERRMSG("Cannot open file!");
4336
4337 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
4338 ctl->metbase, ctl->dt_met, filename);
4339 if (!mptrac_read_met(filename, ctl, clim, *met1))
4340 ERRMSG("Cannot open file!");
4341
4342 /* Update GPU... */
4343 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
4344 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4345
4346 /* Caching... */
4347 if (ctl->met_cache && t != ctl->t_stop) {
4348 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
4349 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
4350 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4351 LOG(1, "Caching: %s", cachefile);
4352 if (system(cmd) != 0)
4353 WARN("Caching command failed!");
4354 }
4355 }
4356
4357 /* Read new data for forward trajectories... */
4358 if (t > (*met1)->time) {
4359
4360 /* Pointer swap... */
4361 mets = *met1;
4362 *met1 = *met0;
4363 *met0 = mets;
4364
4365 /* Read new meteo data... */
4366 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
4367 if (!mptrac_read_met(filename, ctl, clim, *met1))
4368 ERRMSG("Cannot open file!");
4369
4370 /* Update GPU... */
4371 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
4372 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4373
4374 /* Caching... */
4375 if (ctl->met_cache && t != ctl->t_stop) {
4376 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
4377 cachefile);
4378 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4379 LOG(1, "Caching: %s", cachefile);
4380 if (system(cmd) != 0)
4381 WARN("Caching command failed!");
4382 }
4383 }
4384
4385 /* Read new data for backward trajectories... */
4386 if (t < (*met0)->time) {
4387
4388 /* Pointer swap... */
4389 mets = *met1;
4390 *met1 = *met0;
4391 *met0 = mets;
4392
4393 /* Read new meteo data... */
4394 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
4395 if (!mptrac_read_met(filename, ctl, clim, *met0))
4396 ERRMSG("Cannot open file!");
4397
4398 /* Update GPU... */
4399 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
4400 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4401
4402 /* Caching... */
4403 if (ctl->met_cache && t != ctl->t_stop) {
4404 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
4405 cachefile);
4406 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4407 LOG(1, "Caching: %s", cachefile);
4408 if (system(cmd) != 0)
4409 WARN("Caching command failed!");
4410 }
4411 }
4412
4413 /* Check that grids are consistent... */
4414 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
4415 if ((*met0)->nx != (*met1)->nx
4416 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
4417 ERRMSG("Meteo grid dimensions do not match!");
4418 for (int ix = 0; ix < (*met0)->nx; ix++)
4419 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
4420 ERRMSG("Meteo grid longitudes do not match!");
4421 for (int iy = 0; iy < (*met0)->ny; iy++)
4422 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
4423 ERRMSG("Meteo grid latitudes do not match!");
4424 for (int ip = 0; ip < (*met0)->np; ip++)
4425 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
4426 ERRMSG("Meteo grid pressure levels do not match!");
4427 }
4428}
int mptrac_read_met(const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met)
Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.
Definition: mptrac.c:5418
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:1048
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:1882
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2646
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2480
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 4432 of file mptrac.c.

4437 {
4438
4439 /* Initialize timesteps... */
4440 module_timesteps_init(ctl, atm);
4441
4442 /* Initialize random number generator... */
4443 module_rng_init(ntask);
4444
4445 /* Update GPU memory... */
4446 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
4447}
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4002
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:3704
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 4451 of file mptrac.c.

4454 {
4455
4456 int result;
4457
4458 /* Set timer... */
4459 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
4460
4461 /* Init... */
4462 atm->np = 0;
4463
4464 /* Write info... */
4465 LOG(1, "Read atmospheric data: %s", filename);
4466
4467 /* Read ASCII data... */
4468 if (ctl->atm_type == 0)
4469 result = read_atm_asc(filename, ctl, atm);
4470
4471 /* Read binary data... */
4472 else if (ctl->atm_type == 1)
4473 result = read_atm_bin(filename, ctl, atm);
4474
4475 /* Read netCDF data... */
4476 else if (ctl->atm_type == 2)
4477 result = read_atm_nc(filename, ctl, atm);
4478
4479 /* Read CLaMS data... */
4480 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
4481 result = read_atm_clams(filename, ctl, atm);
4482
4483 /* Error... */
4484 else
4485 ERRMSG("Atmospheric data type not supported!");
4486
4487 /* Check result... */
4488 if (result != 1)
4489 return 0;
4490
4491 /* Check number of air parcels... */
4492 if (atm->np < 1)
4493 ERRMSG("Can not read any data!");
4494
4495 /* Write info... */
4496 double mini, maxi;
4497 LOG(2, "Number of particles: %d", atm->np);
4498 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
4499 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
4500 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
4501 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
4502 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
4503 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
4504 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
4505 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
4506 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
4507 for (int iq = 0; iq < ctl->nq; iq++) {
4508 char msg[5 * LEN];
4509 sprintf(msg, "Quantity %s range: %s ... %s %s",
4510 ctl->qnt_name[iq], ctl->qnt_format[iq],
4511 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
4512 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
4513 LOG(2, msg, mini, maxi);
4514 }
4515
4516 /* Return success... */
4517 return 1;
4518}
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:6113
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:6001
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:6057
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:5959
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2188
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:2948
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2185
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2179
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.
Authors
Lars Hoffmann
Mingzhao Liu

Definition at line 4522 of file mptrac.c.

4524 {
4525
4526 /* Set timer... */
4527 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
4528
4529 /* Init tropopause climatology... */
4530 clim_tropo_init(clim);
4531
4532 /* Read photolysis rates... */
4533 if (ctl->clim_photo[0] != '-')
4534 read_clim_photo(ctl->clim_photo, &clim->photo);
4535
4536 /* Read HNO3 climatology... */
4537 if (ctl->clim_hno3_filename[0] != '-')
4538 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
4539
4540 /* Read OH climatology... */
4541 if (ctl->clim_oh_filename[0] != '-') {
4542 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
4543 if (ctl->oh_chem_beta > 0)
4544 clim_oh_diurnal_correction(ctl, clim);
4545 }
4546
4547 /* Read H2O2 climatology... */
4548 if (ctl->clim_h2o2_filename[0] != '-')
4549 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
4550
4551 /* Read HO2 climatology... */
4552 if (ctl->clim_ho2_filename[0] != '-')
4553 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
4554
4555 /* Read O(1D) climatology... */
4556 if (ctl->clim_o1d_filename[0] != '-')
4557 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
4558
4559 /* Read CFC-10 time series... */
4560 if (ctl->clim_ccl4_timeseries[0] != '-')
4562
4563 /* Read CFC-11 time series... */
4564 if (ctl->clim_ccl3f_timeseries[0] != '-')
4566
4567 /* Read CFC-12 time series... */
4568 if (ctl->clim_ccl2f2_timeseries[0] != '-')
4570
4571 /* Read N2O time series... */
4572 if (ctl->clim_n2o_timeseries[0] != '-')
4573 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
4574
4575 /* Read SF6 time series... */
4576 if (ctl->clim_sf6_timeseries[0] != '-')
4577 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
4578}
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:6146
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:6265
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:6319
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:228
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:116
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2778
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2781
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2766
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2775
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2772
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2769
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 4582 of file mptrac.c.

4586 {
4587
4588 /* Set timer... */
4589 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
4590
4591 /* Write info... */
4592 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
4593 "(executable: %s | version: %s | compiled: %s, %s)\n",
4594 argv[0], VERSION, __DATE__, __TIME__);
4595
4596 /* Initialize quantity indices... */
4597 ctl->qnt_idx = -1;
4598 ctl->qnt_ens = -1;
4599 ctl->qnt_stat = -1;
4600 ctl->qnt_m = -1;
4601 ctl->qnt_vmr = -1;
4602 ctl->qnt_rp = -1;
4603 ctl->qnt_rhop = -1;
4604 ctl->qnt_ps = -1;
4605 ctl->qnt_ts = -1;
4606 ctl->qnt_zs = -1;
4607 ctl->qnt_us = -1;
4608 ctl->qnt_vs = -1;
4609 ctl->qnt_ess = -1;
4610 ctl->qnt_nss = -1;
4611 ctl->qnt_shf = -1;
4612 ctl->qnt_lsm = -1;
4613 ctl->qnt_sst = -1;
4614 ctl->qnt_pbl = -1;
4615 ctl->qnt_pt = -1;
4616 ctl->qnt_tt = -1;
4617 ctl->qnt_zt = -1;
4618 ctl->qnt_h2ot = -1;
4619 ctl->qnt_zg = -1;
4620 ctl->qnt_p = -1;
4621 ctl->qnt_t = -1;
4622 ctl->qnt_rho = -1;
4623 ctl->qnt_u = -1;
4624 ctl->qnt_v = -1;
4625 ctl->qnt_w = -1;
4626 ctl->qnt_h2o = -1;
4627 ctl->qnt_o3 = -1;
4628 ctl->qnt_lwc = -1;
4629 ctl->qnt_rwc = -1;
4630 ctl->qnt_iwc = -1;
4631 ctl->qnt_swc = -1;
4632 ctl->qnt_cc = -1;
4633 ctl->qnt_pct = -1;
4634 ctl->qnt_pcb = -1;
4635 ctl->qnt_cl = -1;
4636 ctl->qnt_plcl = -1;
4637 ctl->qnt_plfc = -1;
4638 ctl->qnt_pel = -1;
4639 ctl->qnt_cape = -1;
4640 ctl->qnt_cin = -1;
4641 ctl->qnt_o3c = -1;
4642 ctl->qnt_hno3 = -1;
4643 ctl->qnt_oh = -1;
4644 ctl->qnt_h2o2 = -1;
4645 ctl->qnt_ho2 = -1;
4646 ctl->qnt_o1d = -1;
4647 ctl->qnt_mloss_oh = -1;
4648 ctl->qnt_mloss_h2o2 = -1;
4649 ctl->qnt_mloss_kpp = -1;
4650 ctl->qnt_mloss_wet = -1;
4651 ctl->qnt_mloss_dry = -1;
4652 ctl->qnt_mloss_decay = -1;
4653 ctl->qnt_loss_rate = -1;
4654 ctl->qnt_psat = -1;
4655 ctl->qnt_psice = -1;
4656 ctl->qnt_pw = -1;
4657 ctl->qnt_sh = -1;
4658 ctl->qnt_rh = -1;
4659 ctl->qnt_rhice = -1;
4660 ctl->qnt_theta = -1;
4661 ctl->qnt_zeta = -1;
4662 ctl->qnt_zeta_d = -1;
4663 ctl->qnt_tvirt = -1;
4664 ctl->qnt_lapse = -1;
4665 ctl->qnt_vh = -1;
4666 ctl->qnt_vz = -1;
4667 ctl->qnt_pv = -1;
4668 ctl->qnt_tdew = -1;
4669 ctl->qnt_tice = -1;
4670 ctl->qnt_tsts = -1;
4671 ctl->qnt_tnat = -1;
4672 ctl->qnt_Cx = -1;
4673 ctl->qnt_Ch2o = -1;
4674 ctl->qnt_Co3 = -1;
4675 ctl->qnt_Cco = -1;
4676 ctl->qnt_Coh = -1;
4677 ctl->qnt_Ch = -1;
4678 ctl->qnt_Cho2 = -1;
4679 ctl->qnt_Ch2o2 = -1;
4680 ctl->qnt_Co1d = -1;
4681 ctl->qnt_Co3p = -1;
4682 ctl->qnt_Cccl4 = -1;
4683 ctl->qnt_Cccl3f = -1;
4684 ctl->qnt_Cccl2f2 = -1;
4685 ctl->qnt_Cn2o = -1;
4686 ctl->qnt_Csf6 = -1;
4687 ctl->qnt_aoa = -1;
4688
4689 /* Read quantities... */
4690 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
4691 if (ctl->nq > NQ)
4692 ERRMSG("Too many quantities!");
4693 for (int iq = 0; iq < ctl->nq; iq++) {
4694
4695 /* Read quantity name and format... */
4696 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
4697 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
4698 ctl->qnt_longname[iq]);
4699 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
4700 ctl->qnt_format[iq]);
4701 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
4702 sprintf(ctl->qnt_format[iq], "%%.2f");
4703
4704 /* Try to identify quantity... */
4705 SET_QNT(qnt_idx, "idx", "particle index", "-")
4706 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
4707 SET_QNT(qnt_stat, "stat", "station flag", "-")
4708 SET_QNT(qnt_m, "m", "mass", "kg")
4709 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
4710 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
4711 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
4712 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
4713 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
4714 SET_QNT(qnt_zs, "zs", "surface height", "km")
4715 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
4716 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
4717 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
4718 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
4719 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
4720 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
4721 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
4722 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
4723 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
4724 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
4725 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
4726 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
4727 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
4728 SET_QNT(qnt_p, "p", "pressure", "hPa")
4729 SET_QNT(qnt_t, "t", "temperature", "K")
4730 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
4731 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
4732 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
4733 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
4734 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
4735 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
4736 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
4737 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
4738 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
4739 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
4740 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
4741 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
4742 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
4743 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
4744 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
4745 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
4746 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
4747 SET_QNT(qnt_cape, "cape", "convective available potential energy",
4748 "J/kg")
4749 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
4750 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
4751 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
4752 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
4753 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
4754 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
4755 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
4756 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
4757 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2", "mass loss due to H2O2 chemistry",
4758 "kg")
4759 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
4760 "kg")
4761 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
4762 "kg")
4763 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
4764 "kg")
4765 SET_QNT(qnt_mloss_decay, "mloss_decay",
4766 "mass loss due to exponential decay", "kg")
4767 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
4768 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
4769 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
4770 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
4771 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
4772 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
4773 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
4774 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
4775 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
4776 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
4777 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
4778 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
4779 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
4780 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
4781 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
4782 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
4783 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
4784 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
4785 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
4786 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
4787 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
4788 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
4789 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
4790 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
4791 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
4792 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
4793 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
4794 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
4795 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
4796 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
4797 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
4798 "ppv")
4799 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
4800 "ppv")
4801 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
4802 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
4803 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
4804 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
4805 }
4806
4807 /* Vertical coordinates and velocities... */
4808 ctl->advect_vert_coord =
4809 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
4810 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 2)
4811 ERRMSG("Set ADVECT_VERT_COORD to 0, 1, or 2!");
4812 ctl->met_vert_coord =
4813 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
4814 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
4815 ERRMSG("Set MET_VERT_COORD to 0, 1, 2, 3, or 4!");
4816 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
4817 ERRMSG("Please add zeta to your quantities for diabatic calculations!");
4818 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
4819 ERRMSG
4820 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
4821
4822 /* Time steps of simulation... */
4823 ctl->direction =
4824 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
4825 if (ctl->direction != -1 && ctl->direction != 1)
4826 ERRMSG("Set DIRECTION to -1 or 1!");
4827 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
4828 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
4829
4830 /* Meteo data... */
4831 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
4832 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
4833 ctl->met_convention =
4834 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
4835 ctl->met_type =
4836 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
4837 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
4838 ERRMSG
4839 ("Please use meteo files in netcdf format for diabatic calculations.");
4840 ctl->met_clams =
4841 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
4842 ctl->met_nc_scale =
4843 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
4844 ctl->met_nc_level =
4845 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
4846 ctl->met_nc_quant =
4847 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
4848 ctl->met_zstd_level =
4849 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
4850 ctl->met_zfp_prec =
4851 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", -1, "8", NULL);
4852 ctl->met_zfp_tol_t =
4853 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_T", -1, "5.0", NULL);
4854 ctl->met_zfp_tol_z =
4855 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_Z", -1, "0.5", NULL);
4856 ctl->met_cms_batch =
4857 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
4858 ctl->met_cms_zstd =
4859 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
4860 ctl->met_cms_heur =
4861 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
4862 ctl->met_cms_eps_z =
4863 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
4864 ctl->met_cms_eps_t =
4865 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
4866 ctl->met_cms_eps_u =
4867 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
4868 ctl->met_cms_eps_v =
4869 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
4870 ctl->met_cms_eps_w =
4871 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
4872 ctl->met_cms_eps_pv =
4873 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
4874 ctl->met_cms_eps_h2o =
4875 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
4876 ctl->met_cms_eps_o3 =
4877 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
4878 ctl->met_cms_eps_lwc =
4879 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
4880 ctl->met_cms_eps_rwc =
4881 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
4882 ctl->met_cms_eps_iwc =
4883 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
4884 ctl->met_cms_eps_swc =
4885 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
4886 ctl->met_cms_eps_cc =
4887 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
4888 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
4889 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
4890 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
4891 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
4892 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
4893 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
4894 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
4895 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
4896 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
4897 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
4898 ctl->met_detrend =
4899 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
4900 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
4901 if (ctl->met_np > EP)
4902 ERRMSG("Too many pressure levels!");
4903 ctl->met_press_level_def =
4904 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
4905 NULL);
4906 if (ctl->met_press_level_def >= 0) {
4907 level_definitions(ctl);
4908 } else {
4909 if (ctl->met_np > 0) {
4910 for (int ip = 0; ip < ctl->met_np; ip++)
4911 ctl->met_p[ip] =
4912 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
4913 }
4914 }
4915 ctl->met_nlev =
4916 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
4917 if (ctl->met_nlev > EP)
4918 ERRMSG("Too many model levels!");
4919 for (int ip = 0; ip < ctl->met_nlev; ip++) {
4920 ctl->met_lev_hyam[ip] =
4921 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
4922 ctl->met_lev_hybm[ip] =
4923 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
4924 }
4925 ctl->met_geopot_sx =
4926 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
4927 ctl->met_geopot_sy =
4928 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
4929 ctl->met_relhum =
4930 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
4931 ctl->met_cape =
4932 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
4933 if (ctl->met_cape < 0 || ctl->met_cape > 1)
4934 ERRMSG("Set MET_CAPE to 0 or 1!");
4935 ctl->met_pbl =
4936 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
4937 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
4938 ERRMSG("Set MET_PBL to 0 ... 3!");
4939 ctl->met_pbl_min =
4940 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
4941 ctl->met_pbl_max =
4942 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
4943 ctl->met_tropo =
4944 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
4945 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
4946 ERRMSG("Set MET_TROPO to 0 ... 5!");
4947 ctl->met_tropo_pv =
4948 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
4949 ctl->met_tropo_theta =
4950 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
4951 ctl->met_tropo_spline =
4952 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
4953 ctl->met_dt_out =
4954 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
4955 ctl->met_cache =
4956 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
4957 ctl->met_mpi_share =
4958 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
4959
4960 /* Sorting... */
4961 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
4962
4963 /* Isosurface parameters... */
4964 ctl->isosurf =
4965 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
4966 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
4967
4968 /* Random number generator... */
4969 ctl->rng_type =
4970 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
4971 if (ctl->rng_type < 0 || ctl->rng_type > 2)
4972 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
4973
4974 /* Advection parameters... */
4975 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
4976 if (!(ctl->advect == 0 || ctl->advect == 1
4977 || ctl->advect == 2 || ctl->advect == 4))
4978 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
4979
4980 /* Diffusion parameters... */
4981 ctl->diffusion
4982 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
4983 if (ctl->diffusion < 0 || ctl->diffusion > 2)
4984 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
4985 ctl->turb_dx_pbl =
4986 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
4987 ctl->turb_dx_trop =
4988 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
4989 ctl->turb_dx_strat =
4990 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
4991 ctl->turb_dz_pbl =
4992 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
4993 ctl->turb_dz_trop =
4994 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
4995 ctl->turb_dz_strat =
4996 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
4997 ctl->turb_mesox =
4998 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
4999 ctl->turb_mesoz =
5000 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5001
5002 /* Convection... */
5003 ctl->conv_mix_pbl
5004 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5005 ctl->conv_pbl_trans
5006 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5007 ctl->conv_cape
5008 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5009 ctl->conv_cin
5010 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5011 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5012
5013 /* Boundary conditions... */
5014 ctl->bound_mass =
5015 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5016 ctl->bound_mass_trend =
5017 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5018 ctl->bound_vmr =
5019 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5020 ctl->bound_vmr_trend =
5021 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5022 ctl->bound_lat0 =
5023 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5024 ctl->bound_lat1 =
5025 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5026 ctl->bound_p0 =
5027 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5028 ctl->bound_p1 =
5029 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5030 ctl->bound_dps =
5031 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5032 ctl->bound_dzs =
5033 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5034 ctl->bound_zetas =
5035 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5036 ctl->bound_pbl =
5037 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5038
5039 /* Species parameters... */
5040 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5041 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5042 ctl->molmass = 120.907;
5043 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5044 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5045 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5046 ctl->molmass = 137.359;
5047 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5048 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5049 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5050 ctl->molmass = 16.043;
5051 ctl->oh_chem_reaction = 2;
5052 ctl->oh_chem[0] = 2.45e-12;
5053 ctl->oh_chem[1] = 1775;
5054 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5055 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5056 } else if (strcasecmp(ctl->species, "CO") == 0) {
5057 ctl->molmass = 28.01;
5058 ctl->oh_chem_reaction = 3;
5059 ctl->oh_chem[0] = 6.9e-33;
5060 ctl->oh_chem[1] = 2.1;
5061 ctl->oh_chem[2] = 1.1e-12;
5062 ctl->oh_chem[3] = -1.3;
5063 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5064 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5065 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5066 ctl->molmass = 44.009;
5067 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5068 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5069 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5070 ctl->molmass = 18.01528;
5071 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5072 ctl->molmass = 44.013;
5073 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5074 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5075 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5076 ctl->molmass = 17.031;
5077 ctl->oh_chem_reaction = 2;
5078 ctl->oh_chem[0] = 1.7e-12;
5079 ctl->oh_chem[1] = 710;
5080 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5081 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5082 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5083 ctl->molmass = 63.012;
5084 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5085 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5086 } else if (strcasecmp(ctl->species, "NO") == 0) {
5087 ctl->molmass = 30.006;
5088 ctl->oh_chem_reaction = 3;
5089 ctl->oh_chem[0] = 7.1e-31;
5090 ctl->oh_chem[1] = 2.6;
5091 ctl->oh_chem[2] = 3.6e-11;
5092 ctl->oh_chem[3] = 0.1;
5093 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5094 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5095 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5096 ctl->molmass = 46.005;
5097 ctl->oh_chem_reaction = 3;
5098 ctl->oh_chem[0] = 1.8e-30;
5099 ctl->oh_chem[1] = 3.0;
5100 ctl->oh_chem[2] = 2.8e-11;
5101 ctl->oh_chem[3] = 0.0;
5102 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5103 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5104 } else if (strcasecmp(ctl->species, "O3") == 0) {
5105 ctl->molmass = 47.997;
5106 ctl->oh_chem_reaction = 2;
5107 ctl->oh_chem[0] = 1.7e-12;
5108 ctl->oh_chem[1] = 940;
5109 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5110 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5111 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5112 ctl->molmass = 146.048;
5113 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5114 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5115 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5116 ctl->molmass = 64.066;
5117 ctl->oh_chem_reaction = 3;
5118 ctl->oh_chem[0] = 2.9e-31;
5119 ctl->oh_chem[1] = 4.1;
5120 ctl->oh_chem[2] = 1.7e-12;
5121 ctl->oh_chem[3] = -0.2;
5122 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5123 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5124 }
5125
5126 /* Molar mass... */
5127 char defstr[LEN];
5128 sprintf(defstr, "%g", ctl->molmass);
5129 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5130
5131 /* OH chemistry... */
5132 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5133 ctl->oh_chem_reaction =
5134 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5135 NULL);
5136 for (int ip = 0; ip < 4; ip++) {
5137 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5138 ctl->oh_chem[ip] =
5139 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5140 }
5141 ctl->oh_chem_beta =
5142 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5143
5144 /* H2O2 chemistry... */
5145 ctl->h2o2_chem_reaction =
5146 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5147
5148 /* KPP chemistry... */
5149 ctl->kpp_chem =
5150 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5151 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5152
5153 /* First order tracer chemistry... */
5154 ctl->tracer_chem =
5155 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5156
5157 /* Wet deposition... */
5158 for (int ip = 0; ip < 2; ip++) {
5159 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5160 ctl->wet_depo_ic_h[ip] =
5161 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5162 }
5163 for (int ip = 0; ip < 1; ip++) {
5164 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5165 ctl->wet_depo_bc_h[ip] =
5166 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5167 }
5168 ctl->wet_depo_so2_ph =
5169 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
5170 ctl->wet_depo_ic_a =
5171 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5172 ctl->wet_depo_ic_b =
5173 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5174 ctl->wet_depo_bc_a =
5175 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5176 ctl->wet_depo_bc_b =
5177 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5178 ctl->wet_depo_pre[0] =
5179 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5180 ctl->wet_depo_pre[1] =
5181 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5183 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5185 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5186
5187 /* Dry deposition... */
5188 ctl->dry_depo_vdep =
5189 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5190 ctl->dry_depo_dp =
5191 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5192
5193 /* Climatological data... */
5194 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5195 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5196 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5197 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5198 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5199 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5200 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5201 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5202 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5203 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5204 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5205 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5206 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5207 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5208 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5209 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5210 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5211 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5212 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5213 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5214 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5215 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5216
5217 /* Mixing... */
5218 ctl->mixing_dt =
5219 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5220 ctl->mixing_trop =
5221 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5222 ctl->mixing_strat =
5223 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5224 ctl->mixing_z0 =
5225 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5226 ctl->mixing_z1 =
5227 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5228 ctl->mixing_nz =
5229 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5230 ctl->mixing_lon0 =
5231 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5232 ctl->mixing_lon1 =
5233 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5234 ctl->mixing_nx =
5235 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5236 ctl->mixing_lat0 =
5237 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5238 ctl->mixing_lat1 =
5239 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5240 ctl->mixing_ny =
5241 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5242
5243 /* Chemistry grid... */
5244 ctl->chemgrid_z0 =
5245 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5246 ctl->chemgrid_z1 =
5247 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5248 ctl->chemgrid_nz =
5249 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5250 ctl->chemgrid_lon0 =
5251 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5252 ctl->chemgrid_lon1 =
5253 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5254 ctl->chemgrid_nx =
5255 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5256 ctl->chemgrid_lat0 =
5257 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5258 ctl->chemgrid_lat1 =
5259 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5260 ctl->chemgrid_ny =
5261 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5262
5263 /* Exponential decay... */
5264 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5265 ctl->tdec_strat
5266 = scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5267
5268 /* PSC analysis... */
5269 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5270 ctl->psc_hno3 =
5271 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5272
5273 /* Output of atmospheric data... */
5274 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5275 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5276 ctl->atm_dt_out =
5277 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5278 ctl->atm_filter =
5279 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5280 ctl->atm_stride =
5281 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5282 ctl->atm_type =
5283 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
5284 ctl->atm_type_out =
5285 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
5286 if (ctl->atm_type_out == -1)
5287 ctl->atm_type_out = ctl->atm_type;
5288 ctl->atm_nc_level =
5289 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
5290 for (int iq = 0; iq < ctl->nq; iq++)
5291 ctl->atm_nc_quant[iq] =
5292 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
5293 ctl->obs_type =
5294 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
5295
5296 /* Output of CSI data... */
5297 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
5298 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
5299 ctl->csi_dt_out =
5300 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
5301 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
5302 ctl->csi_obsmin =
5303 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
5304 ctl->csi_modmin =
5305 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
5306 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
5307 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
5308 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
5309 ctl->csi_lon0 =
5310 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
5311 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
5312 ctl->csi_nx =
5313 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
5314 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
5315 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
5316 ctl->csi_ny =
5317 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
5318
5319 /* Output of ensemble data... */
5320 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
5321 ctl->ens_dt_out =
5322 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
5323
5324 /* Output of grid data... */
5325 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
5326 ctl->grid_basename);
5327 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
5328 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
5329 ctl->grid_dt_out =
5330 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
5331 ctl->grid_sparse =
5332 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
5333 ctl->grid_nc_level =
5334 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
5335 for (int iq = 0; iq < ctl->nq; iq++)
5336 ctl->grid_nc_quant[iq] =
5337 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
5338 ctl->grid_stddev =
5339 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
5340 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
5341 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
5342 ctl->grid_nz =
5343 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
5344 ctl->grid_lon0 =
5345 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
5346 ctl->grid_lon1 =
5347 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
5348 ctl->grid_nx =
5349 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
5350 ctl->grid_lat0 =
5351 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
5352 ctl->grid_lat1 =
5353 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
5354 ctl->grid_ny =
5355 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
5356 ctl->grid_type =
5357 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
5358
5359 /* Output of profile data... */
5360 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
5361 ctl->prof_basename);
5362 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
5363 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
5364 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
5365 ctl->prof_nz =
5366 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
5367 ctl->prof_lon0 =
5368 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
5369 ctl->prof_lon1 =
5370 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
5371 ctl->prof_nx =
5372 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
5373 ctl->prof_lat0 =
5374 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
5375 ctl->prof_lat1 =
5376 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
5377 ctl->prof_ny =
5378 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
5379
5380 /* Output of sample data... */
5381 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
5382 ctl->sample_basename);
5383 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
5384 ctl->sample_kernel);
5385 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
5386 ctl->sample_obsfile);
5387 ctl->sample_dx =
5388 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
5389 ctl->sample_dz =
5390 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
5391
5392 /* Output of station data... */
5393 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
5394 ctl->stat_basename);
5395 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
5396 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
5397 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
5398 ctl->stat_t0 =
5399 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
5400 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
5401
5402 /* Output of VTK data... */
5403 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
5404 ctl->vtk_dt_out =
5405 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
5406 ctl->vtk_stride =
5407 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
5408 ctl->vtk_scale =
5409 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
5410 ctl->vtk_offset =
5411 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
5412 ctl->vtk_sphere =
5413 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
5414}
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:1817
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:8989
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:262
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1534
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3043
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2281
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3007
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:2974
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2314
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:2983
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2260
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2935
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2293
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:2977
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2302
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:2998
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2269
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3121
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2656
double stat_r
Search radius around station [km].
Definition: mptrac.h:3127
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3001
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3151
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2624
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2290
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2368
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3070
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3046
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2643
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2332
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2395
char species[LEN]
Species.
Definition: mptrac.h:2754
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:2992
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3004
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2621
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2284
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3031
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3049
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3061
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2215
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2311
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3052
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2338
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2640
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3106
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2389
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2612
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3022
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2236
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2380
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3133
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:2968
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3067
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:2995
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2242
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3037
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2365
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2609
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2212
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3073
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2218
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3076
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:2971
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2618
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:2980
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3019
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3079
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2275
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2634
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3085
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2197
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2649
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2398
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2335
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:2989
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3130
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:2953
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2600
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2880
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:2965
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2233
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2224
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3139
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2715
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3109
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2326
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3016
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2254
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2374
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2627
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2386
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2883
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2676
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2257
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3148
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2272
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2329
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2278
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3094
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2377
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2266
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3115
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:2962
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3034
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2221
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3055
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2932
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2245
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2305
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3082
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2603
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2263
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:2941
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2877
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3010
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:2986
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2392
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3124
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3058
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2317
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2323
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3040
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2230
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3013
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3103
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:2944
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2615
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2938
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3100
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2922
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3088
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2299
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2347
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2362
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2606
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3097
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2320
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2925
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3091
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2874
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2959
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3028
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3136
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2248
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2194
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2802
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3145
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2401
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2239
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2956
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2371
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2227
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2191
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2637
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2287
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2182
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3112
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3142
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3118
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3064
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2251
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2296
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2308
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3025
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2404
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 
)

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, the data is read from a binary file using the read_met_bin function.
  • If the met_type is not recognized, an error message is generated.
Author
Lars Hoffmann

Definition at line 5418 of file mptrac.c.

5422 {
5423
5424 /* Write info... */
5425 LOG(1, "Read meteo data: %s", filename);
5426
5427 /* Set rank... */
5428 int rank = 0;
5429#ifdef MPI
5430 if (ctl->met_mpi_share)
5431 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5432#endif
5433
5434 /* Check rank... */
5435 if (!ctl->met_mpi_share || rank == 0) {
5436
5437 /* Read netCDF data... */
5438 if (ctl->met_type == 0) {
5439 if (read_met_nc(filename, ctl, clim, met) != 1)
5440 return 0;
5441 }
5442
5443 /* Read binary data... */
5444 else if (ctl->met_type >= 1 && ctl->met_type <= 5) {
5445 if (read_met_bin(filename, ctl, met) != 1)
5446 return 0;
5447 }
5448
5449 /* Not implemented... */
5450 else
5451 ERRMSG("MET_TYPE not implemented!");
5452 }
5453
5454 /* Broadcast data via MPI... */
5455#ifdef MPI
5456 if (ctl->met_mpi_share) {
5457
5458 /* Set timer... */
5459 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
5460 LOG(2, "Broadcast data on rank %d...", rank);
5461
5462 /* Broadcast... */
5463 broadcast_large_data(met, sizeof(met_t));
5464 }
5465#endif
5466
5467 /* Return success... */
5468 return 1;
5469}
int read_met_nc(const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met)
Reads meteorological data from a NetCDF file and processes it.
Definition: mptrac.c:7641
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:6459
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 
)

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.
Authors
Lars Hoffmann

Definition at line 5473 of file mptrac.c.

5480 {
5481
5482 /* Initialize modules... */
5483 if (t == ctl->t_start) {
5484
5485 /* Initialize isosurface data... */
5486 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5487 module_isosurf_init(ctl, cache, *met0, *met1, atm);
5488
5489 /* Initialize advection... */
5490 module_advect_init(ctl, cache, *met0, *met1, atm);
5491
5492 /* Initialize chemistry... */
5493 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
5494 }
5495
5496 /* Set time steps of air parcels... */
5497 module_timesteps(ctl, cache, *met0, atm, t);
5498
5499 /* Sort particles... */
5500 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
5501 module_sort(ctl, *met0, atm);
5502
5503 /* Check positions (initial)... */
5504 module_position(cache, *met0, *met1, atm);
5505
5506 /* Advection... */
5507 if (ctl->advect > 0)
5508 module_advect(ctl, cache, *met0, *met1, atm);
5509
5510 /* Turbulent diffusion... */
5511 if (ctl->diffusion == 1
5512 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
5513 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
5514 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
5515 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
5516
5517 /* Mesoscale diffusion... */
5518 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
5519 module_diff_meso(ctl, cache, *met0, *met1, atm);
5520
5521 /* Diffusion... */
5522 if (ctl->diffusion == 2)
5523 module_diff_pbl(ctl, cache, *met0, *met1, atm);
5524
5525 /* Convection... */
5526 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
5527 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
5528 module_convection(ctl, cache, *met0, *met1, atm);
5529
5530 /* Sedimentation... */
5531 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
5532 module_sedi(ctl, cache, *met0, *met1, atm);
5533
5534 /* Isosurface... */
5535 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5536 module_isosurf(ctl, cache, *met0, *met1, atm);
5537
5538 /* Check positions (final)... */
5539 module_position(cache, *met0, *met1, atm);
5540
5541 /* Interpolate meteo data... */
5542 if (ctl->met_dt_out > 0
5543 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
5544 module_meteo(ctl, cache, clim, *met0, *met1, atm);
5545
5546 /* Check boundary conditions (initial)... */
5547 if ((ctl->bound_lat0 < ctl->bound_lat1)
5548 && (ctl->bound_p0 > ctl->bound_p1))
5549 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5550
5551 /* Initialize quantity of total loss rate... */
5552 if (ctl->qnt_loss_rate >= 0) {
5553 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
5554 atm->q[ctl->qnt_loss_rate][ip] = 0;
5555 }
5556 }
5557
5558 /* Decay of particle mass... */
5559 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
5560 module_decay(ctl, cache, clim, atm);
5561
5562 /* Interparcel mixing... */
5563 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
5564 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
5565 module_mixing(ctl, clim, atm, t);
5566
5567 /* Calculate the tracer vmr in the chemistry grid... */
5568 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
5569 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
5570 module_chem_grid(ctl, *met0, *met1, atm, t);
5571
5572 /* OH chemistry... */
5573 if (ctl->oh_chem_reaction != 0)
5574 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
5575
5576 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
5577 if (ctl->h2o2_chem_reaction != 0)
5578 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
5579
5580 /* First-order tracer chemistry... */
5581 if (ctl->tracer_chem)
5582 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
5583
5584 /* KPP chemistry... */
5585 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
5586#ifdef KPP
5587 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
5588#else
5589 ERRMSG("Code was compiled without KPP!");
5590#endif
5591 }
5592
5593 /* Wet deposition... */
5594 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
5595 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
5596 module_wet_depo(ctl, cache, *met0, *met1, atm);
5597
5598 /* Dry deposition... */
5599 if (ctl->dry_depo_vdep > 0)
5600 module_dry_depo(ctl, cache, *met0, *met1, atm);
5601
5602 /* Check boundary conditions (final)... */
5603 if ((ctl->bound_lat0 < ctl->bound_lat1)
5604 && (ctl->bound_p0 > ctl->bound_p1))
5605 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5606}
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:2130
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:3965
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:3281
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:2667
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:2552
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:3385
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:3106
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:4103
void module_chem_grid(const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double tt)
Calculate grid data for chemistry modules.
Definition: mptrac.c:2405
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:3840
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:2594
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:2309
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:2282
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:3653
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:2706
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:3869
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:2908
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:4033
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:3023
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:2783
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:3176
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:3569
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:2960
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.
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 5610 of file mptrac.c.

5616 {
5617
5618 /* Update GPU... */
5619 if (ctl != NULL) {
5620#ifdef _OPENACC
5621 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5622#pragma acc update device(ctl[:1])
5623#endif
5624 }
5625
5626 if (cache != NULL) {
5627#ifdef _OPENACC
5628 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5629#pragma acc update device(cache[:1])
5630#endif
5631 }
5632
5633 if (clim != NULL) {
5634#ifdef _OPENACC
5635 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5636#pragma acc update device(clim[:1])
5637#endif
5638 }
5639
5640 if (met0 != NULL) {
5641#ifdef _OPENACC
5642 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5643 met_t *met0up = *met0;
5644#pragma acc update device(met0up[:1])
5645#endif
5646 }
5647
5648 if (met1 != NULL) {
5649#ifdef _OPENACC
5650 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5651 met_t *met1up = *met1;
5652#pragma acc update device(met1up[:1])
5653#endif
5654 }
5655
5656 if (atm != NULL) {
5657#ifdef _OPENACC
5658 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5659#pragma acc update device(atm[:1])
5660#endif
5661 }
5662}

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

5672 {
5673
5674 /* Update GPU... */
5675 if (ctl != NULL) {
5676#ifdef _OPENACC
5677 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5678#pragma acc update host(ctl[:1])
5679#endif
5680 }
5681
5682 if (cache != NULL) {
5683#ifdef _OPENACC
5684 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5685#pragma acc update host(cache[:1])
5686#endif
5687 }
5688
5689 if (clim != NULL) {
5690#ifdef _OPENACC
5691 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5692#pragma acc update host(clim[:1])
5693#endif
5694 }
5695
5696 if (met0 != NULL) {
5697#ifdef _OPENACC
5698 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5699 met_t *met0up = *met0;
5700#pragma acc update host(met0up[:1])
5701#endif
5702 }
5703
5704 if (met1 != NULL) {
5705#ifdef _OPENACC
5706 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5707 met_t *met1up = *met1;
5708#pragma acc update host(met1up[:1])
5709#endif
5710 }
5711
5712 if (atm != NULL) {
5713#ifdef _OPENACC
5714 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5715#pragma acc update host(atm[:1])
5716#endif
5717 }
5718}

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

5726 {
5727
5728 /* Set timer... */
5729 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
5730
5731 /* Write info... */
5732 LOG(1, "Write atmospheric data: %s", filename);
5733
5734 /* Write ASCII data... */
5735 if (ctl->atm_type_out == 0)
5736 write_atm_asc(filename, ctl, atm, t);
5737
5738 /* Write binary data... */
5739 else if (ctl->atm_type_out == 1)
5740 write_atm_bin(filename, ctl, atm);
5741
5742 /* Write netCDF data... */
5743 else if (ctl->atm_type_out == 2)
5744 write_atm_nc(filename, ctl, atm);
5745
5746 /* Write CLaMS trajectory data... */
5747 else if (ctl->atm_type_out == 3)
5748 write_atm_clams_traj(filename, ctl, atm, t);
5749
5750 /* Write CLaMS pos data... */
5751 else if (ctl->atm_type_out == 4)
5752 write_atm_clams(filename, ctl, atm);
5753
5754 /* Error... */
5755 else
5756 ERRMSG("Atmospheric data type not supported!");
5757
5758 /* Write info... */
5759 double mini, maxi;
5760 LOG(2, "Number of particles: %d", atm->np);
5761 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5762 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5763 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5764 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5765 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5766 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5767 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5768 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5769 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5770 for (int iq = 0; iq < ctl->nq; iq++) {
5771 char msg[5 * LEN];
5772 sprintf(msg, "Quantity %s range: %s ... %s %s",
5773 ctl->qnt_name[iq], ctl->qnt_format[iq],
5774 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5775 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5776 LOG(2, msg, mini, maxi);
5777 }
5778}
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:9545
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:9360
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:9492
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:9442
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:9703
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.
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, 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 5782 of file mptrac.c.

5785 {
5786
5787 /* Set timer... */
5788 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
5789
5790 /* Write info... */
5791 LOG(1, "Write meteo data: %s", filename);
5792
5793 /* Check compression flags... */
5794#ifndef ZFP
5795 if (ctl->met_type == 3)
5796 ERRMSG("MPTRAC was compiled without zfp compression!");
5797#endif
5798#ifndef ZSTD
5799 if (ctl->met_type == 4)
5800 ERRMSG("MPTRAC was compiled without zstd compression!");
5801#endif
5802#ifndef CMS
5803 if (ctl->met_type == 5)
5804 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
5805#endif
5806
5807 /* Write netCDF data... */
5808 if (ctl->met_type == 0)
5809 write_met_nc(filename, ctl, met);
5810
5811 /* Write binary data... */
5812 else if (ctl->met_type >= 1 && ctl->met_type <= 5)
5813 write_met_bin(filename, ctl, met);
5814
5815 /* Not implemented... */
5816 else
5817 ERRMSG("MET_TYPE not implemented!");
5818}
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:10742
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:10536
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 5822 of file mptrac.c.

5828 {
5829
5830 char ext[10], filename[2 * LEN];
5831
5832 double r;
5833
5834 int year, mon, day, hour, min, sec;
5835
5836 /* Get time... */
5837 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
5838
5839 /* Update host... */
5840 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
5841 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
5842 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
5843 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
5844 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
5845 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
5846 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
5847
5848 /* Write atmospheric data... */
5849 if (ctl->atm_basename[0] != '-' &&
5850 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
5851 if (ctl->atm_type_out == 0)
5852 sprintf(ext, "tab");
5853 else if (ctl->atm_type_out == 1)
5854 sprintf(ext, "bin");
5855 else if (ctl->atm_type_out == 2)
5856 sprintf(ext, "nc");
5857 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
5858 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
5859 mptrac_write_atm(filename, ctl, atm, t);
5860 }
5861
5862 /* Write gridded data... */
5863 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
5864 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
5865 dirname, ctl->grid_basename, year, mon, day, hour, min,
5866 ctl->grid_type == 0 ? "tab" : "nc");
5867 write_grid(filename, ctl, met0, met1, atm, t);
5868 }
5869
5870 /* Write CSI data... */
5871 if (ctl->csi_basename[0] != '-') {
5872 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
5873 write_csi(filename, ctl, atm, t);
5874 }
5875
5876 /* Write ensemble data... */
5877 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
5878 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
5879 dirname, ctl->ens_basename, year, mon, day, hour, min);
5880 write_ens(filename, ctl, atm, t);
5881 }
5882
5883 /* Write profile data... */
5884 if (ctl->prof_basename[0] != '-') {
5885 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
5886 write_prof(filename, ctl, met0, met1, atm, t);
5887 }
5888
5889 /* Write sample data... */
5890 if (ctl->sample_basename[0] != '-') {
5891 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
5892 write_sample(filename, ctl, met0, met1, atm, t);
5893 }
5894
5895 /* Write station data... */
5896 if (ctl->stat_basename[0] != '-') {
5897 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
5898 write_station(filename, ctl, atm, t);
5899 }
5900
5901 /* Write VTK data... */
5902 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
5903 static int nvtk;
5904 if (t == ctl->t_start)
5905 nvtk = 0;
5906 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
5907 write_vtk(filename, ctl, atm, t);
5908 }
5909}
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:5722
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:10014
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:10964
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:5666
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:11353
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:11439
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:11191
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:10111
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:9752
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 5913 of file mptrac.c.

5916 {
5917
5918 /* Check water vapor volume mixing ratio... */
5919 const double h2o_help = MAX(h2o, 0.1e-6);
5920
5921 /* Calculate T_NAT... */
5922 const double p_hno3 = hno3 * p / 1.333224;
5923 const double p_h2o = h2o_help * p / 1.333224;
5924 const double a = 0.009179 - 0.00088 * log10(p_h2o);
5925 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
5926 const double c = -11397.0 / a;
5927 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
5928 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
5929 if (x2 > 0)
5930 tnat = x2;
5931
5932 return tnat;
5933}

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

5942 {
5943
5944 /* Get pressure range... */
5945 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
5946 const double p0 = pbl;
5947
5948 /* Get weighting factor... */
5949 if (atm->p[ip] > p0)
5950 return 1;
5951 else if (atm->p[ip] < p1)
5952 return 0;
5953 else
5954 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
5955}

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

5962 {
5963
5964 /* Open file... */
5965 FILE *in;
5966 if (!(in = fopen(filename, "r"))) {
5967 WARN("Cannot open file!");
5968 return 0;
5969 }
5970
5971 /* Read line... */
5972 char line[LEN];
5973 while (fgets(line, LEN, in)) {
5974
5975 /* Read data... */
5976 char *tok;
5977 TOK(line, tok, "%lg", atm->time[atm->np]);
5978 TOK(NULL, tok, "%lg", atm->p[atm->np]);
5979 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
5980 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
5981 for (int iq = 0; iq < ctl->nq; iq++)
5982 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
5983
5984 /* Convert altitude to pressure... */
5985 atm->p[atm->np] = P(atm->p[atm->np]);
5986
5987 /* Increment data point counter... */
5988 if ((++atm->np) > NP)
5989 ERRMSG("Too many data points!");
5990 }
5991
5992 /* Close file... */
5993 fclose(in);
5994
5995 /* Return success... */
5996 return 1;
5997}
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1705

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

6004 {
6005
6006 /* Open file... */
6007 FILE *in;
6008 if (!(in = fopen(filename, "r")))
6009 return 0;
6010
6011 /* Check version of binary data... */
6012 int version;
6013 FREAD(&version, int,
6014 1,
6015 in);
6016 if (version != 100)
6017 ERRMSG("Wrong version of binary data!");
6018
6019 /* Read data... */
6020 FREAD(&atm->np, int,
6021 1,
6022 in);
6023 FREAD(atm->time, double,
6024 (size_t) atm->np,
6025 in);
6026 FREAD(atm->p, double,
6027 (size_t) atm->np,
6028 in);
6029 FREAD(atm->lon, double,
6030 (size_t) atm->np,
6031 in);
6032 FREAD(atm->lat, double,
6033 (size_t) atm->np,
6034 in);
6035 for (int iq = 0; iq < ctl->nq; iq++)
6036 FREAD(atm->q[iq], double,
6037 (size_t) atm->np,
6038 in);
6039
6040 /* Read final flag... */
6041 int final;
6042 FREAD(&final, int,
6043 1,
6044 in);
6045 if (final != 999)
6046 ERRMSG("Error while reading binary data!");
6047
6048 /* Close file... */
6049 fclose(in);
6050
6051 /* Return success... */
6052 return 1;
6053}

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

6060 {
6061
6062 int ncid, varid;
6063
6064 /* Open file... */
6065 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6066 return 0;
6067
6068 /* Get dimensions... */
6069 NC_INQ_DIM("NPARTS", &atm->np, 1, NP);
6070
6071 /* Get time... */
6072 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
6073 NC(nc_get_var_double(ncid, varid, atm->time));
6074 } else {
6075 WARN("TIME_INIT not found use time instead!");
6076 double time_init;
6077 NC_GET_DOUBLE("time", &time_init, 1);
6078 for (int ip = 0; ip < atm->np; ip++) {
6079 atm->time[ip] = time_init;
6080 }
6081 }
6082
6083 /* Read zeta coordinate, pressure is optional... */
6084 if (ctl->advect_vert_coord == 1) {
6085 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
6086 NC_GET_DOUBLE("PRESS", atm->p, 0);
6087 }
6088
6089 /* Read pressure, zeta coordinate is optional... */
6090 else {
6091 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
6092 NC(nc_get_var_double(ncid, varid, atm->p));
6093 } else {
6094 WARN("PRESS_INIT not found use PRESS instead!");
6095 nc_inq_varid(ncid, "PRESS", &varid);
6096 NC(nc_get_var_double(ncid, varid, atm->p));
6097 }
6098 }
6099
6100 /* Read longitude and latitude... */
6101 NC_GET_DOUBLE("LON", atm->lon, 1);
6102 NC_GET_DOUBLE("LAT", atm->lat, 1);
6103
6104 /* Close file... */
6105 NC(nc_close(ncid));
6106
6107 /* Return success... */
6108 return 1;
6109}
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1027
#define NC_INQ_DIM(dimname, ptr, min, max)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1114
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1086

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

6116 {
6117
6118 int ncid, varid;
6119
6120 /* Open file... */
6121 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6122 return 0;
6123
6124 /* Get dimensions... */
6125 NC_INQ_DIM("obs", &atm->np, 1, NP);
6126
6127 /* Read geolocations... */
6128 NC_GET_DOUBLE("time", atm->time, 1);
6129 NC_GET_DOUBLE("press", atm->p, 1);
6130 NC_GET_DOUBLE("lon", atm->lon, 1);
6131 NC_GET_DOUBLE("lat", atm->lat, 1);
6132
6133 /* Read variables... */
6134 for (int iq = 0; iq < ctl->nq; iq++)
6135 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6136
6137 /* Close file... */
6138 NC(nc_close(ncid));
6139
6140 /* Return success... */
6141 return 1;
6142}

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

6148 {
6149
6150 int ncid, varid;
6151
6152 /* Write info... */
6153 LOG(1, "Read photolysis rates: %s", filename);
6154
6155 /* Open netCDF file... */
6156 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6157 WARN("Photolysis rate data are missing!");
6158 return;
6159 }
6160
6161 /* Read pressure data... */
6162 NC_INQ_DIM("press", &photo->np, 2, CP);
6163 NC_GET_DOUBLE("press", photo->p, 1);
6164 if (photo->p[0] < photo->p[1])
6165 ERRMSG("Pressure data are not descending!");
6166
6167 /* Read total column ozone data... */
6168 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3);
6169 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
6170 if (photo->o3c[0] > photo->o3c[1])
6171 ERRMSG("Total column ozone data are not ascending!");
6172
6173 /* Read solar zenith angle data... */
6174 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA);
6175 NC_GET_DOUBLE("sza", photo->sza, 1);
6176 if (photo->sza[0] > photo->sza[1])
6177 ERRMSG("Solar zenith angle data are not ascending!");
6178
6179 /* Read data... */
6180 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
6181 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
6182 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
6183 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
6184 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
6185 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
6186 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
6187 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
6188 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
6189
6190 /* Close netCDF file... */
6191 NC(nc_close(ncid));
6192
6193 /* Write info... */
6194 LOG(2, "Number of pressure levels: %d", photo->np);
6195 LOG(2, "Altitude levels: %g, %g ... %g km",
6196 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
6197 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6198 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
6199 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
6200 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
6201 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
6202 RAD2DEG(photo->sza[photo->nsza - 1]));
6203 LOG(2, "Number of total column ozone values: %d", photo->no3c);
6204 LOG(2, "Total column ozone: %g, %g ... %g DU",
6205 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
6206 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
6207 photo->n2o[0][0][0], photo->n2o[1][0][0],
6208 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6209 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
6210 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
6211 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6212 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
6213 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
6214 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6215 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
6216 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
6217 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6218 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
6219 photo->o2[0][0][0], photo->o2[1][0][0],
6220 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6221 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
6222 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
6223 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6224 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
6225 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
6226 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6227 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
6228 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
6229 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6230 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
6231 photo->h2o[0][0][0], photo->h2o[1][0][0],
6232 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6233}
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:6237
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:312
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:307
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:317
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3259
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3256
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3265
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3268
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3262
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 6237 of file mptrac.c.

6241 {
6242
6243 /* Allocate... */
6244 double *help;
6245 ALLOC(help, double,
6246 photo->np * photo->nsza * photo->no3c);
6247
6248 /* Read varible... */
6249 int varid;
6250 NC_GET_DOUBLE(varname, help, 1);
6251
6252 /* Copy data... */
6253 for (int ip = 0; ip < photo->np; ip++)
6254 for (int is = 0; is < photo->nsza; is++)
6255 for (int io = 0; io < photo->no3c; io++)
6256 var[ip][is][io] =
6257 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
6258
6259 /* Free... */
6260 free(help);
6261}

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

6267 {
6268
6269 /* Write info... */
6270 LOG(1, "Read climatological time series: %s", filename);
6271
6272 /* Open file... */
6273 FILE *in;
6274 if (!(in = fopen(filename, "r"))) {
6275 WARN("Cannot open file!");
6276 return 0;
6277 }
6278
6279 /* Read data... */
6280 char line[LEN];
6281 int nh = 0;
6282 while (fgets(line, LEN, in))
6283 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
6284
6285 /* Convert years to seconds... */
6286 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
6287
6288 /* Check data... */
6289 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
6290 ERRMSG("Time series must be ascending!");
6291
6292 /* Count time steps... */
6293 if ((++nh) >= CTS)
6294 ERRMSG("Too many data points!");
6295 }
6296
6297 /* Close file... */
6298 fclose(in);
6299
6300 /* Check number of data points... */
6301 ts->ntime = nh;
6302 if (nh < 2)
6303 ERRMSG("Not enough data points!");
6304
6305 /* Write info... */
6306 LOG(2, "Number of time steps: %d", ts->ntime);
6307 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
6308 ts->time[nh - 1]);
6309 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
6310 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
6311 (size_t) nh));
6312
6313 /* Exit success... */
6314 return 1;
6315}
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:327

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

6322 {
6323
6324 int ncid, varid, it, iy, iz, iz2, nt;
6325
6326 double *help, varmin = 1e99, varmax = -1e99;
6327
6328 /* Write info... */
6329 LOG(1, "Read %s data: %s", varname, filename);
6330
6331 /* Open netCDF file... */
6332 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6333 WARN("%s climatology data are missing!", varname);
6334 return;
6335 }
6336
6337 /* Read pressure data... */
6338 NC_INQ_DIM("press", &zm->np, 2, CP);
6339 NC_GET_DOUBLE("press", zm->p, 1);
6340 if (zm->p[0] < zm->p[1])
6341 ERRMSG("Pressure data are not descending!");
6342
6343 /* Read latitudes... */
6344 NC_INQ_DIM("lat", &zm->nlat, 2, CY);
6345 NC_GET_DOUBLE("lat", zm->lat, 1);
6346 if (zm->lat[0] > zm->lat[1])
6347 ERRMSG("Latitude data are not ascending!");
6348
6349 /* Set time data (for monthly means)... */
6350 zm->ntime = 12;
6351 zm->time[0] = 1209600.00;
6352 zm->time[1] = 3888000.00;
6353 zm->time[2] = 6393600.00;
6354 zm->time[3] = 9072000.00;
6355 zm->time[4] = 11664000.00;
6356 zm->time[5] = 14342400.00;
6357 zm->time[6] = 16934400.00;
6358 zm->time[7] = 19612800.00;
6359 zm->time[8] = 22291200.00;
6360 zm->time[9] = 24883200.00;
6361 zm->time[10] = 27561600.00;
6362 zm->time[11] = 30153600.00;
6363
6364 /* Check number of timesteps... */
6365 NC_INQ_DIM("time", &nt, 12, 12);
6366
6367 /* Read data... */
6368 ALLOC(help, double,
6369 zm->nlat * zm->np * zm->ntime);
6370 NC_GET_DOUBLE(varname, help, 1);
6371 for (it = 0; it < zm->ntime; it++)
6372 for (iz = 0; iz < zm->np; iz++)
6373 for (iy = 0; iy < zm->nlat; iy++)
6374 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
6375 free(help);
6376
6377 /* Fix data gaps... */
6378 for (it = 0; it < zm->ntime; it++)
6379 for (iy = 0; iy < zm->nlat; iy++)
6380 for (iz = 0; iz < zm->np; iz++) {
6381 if (zm->vmr[it][iz][iy] < 0) {
6382 for (iz2 = 0; iz2 < zm->np; iz2++)
6383 if (zm->vmr[it][iz2][iy] >= 0) {
6384 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6385 break;
6386 }
6387 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
6388 if (zm->vmr[it][iz2][iy] >= 0) {
6389 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6390 break;
6391 }
6392 }
6393 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
6394 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
6395 }
6396
6397 /* Close netCDF file... */
6398 NC(nc_close(ncid));
6399
6400 /* Write info... */
6401 LOG(2, "Number of time steps: %d", zm->ntime);
6402 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
6403 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
6404 LOG(2, "Number of pressure levels: %d", zm->np);
6405 LOG(2, "Altitude levels: %g, %g ... %g km",
6406 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
6407 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
6408 zm->p[1], zm->p[zm->np - 1]);
6409 LOG(2, "Number of latitudes: %d", zm->nlat);
6410 LOG(2, "Latitudes: %g, %g ... %g deg",
6411 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
6412 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
6413 varmax);
6414}
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:302

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

6422 {
6423
6424 /* Write info... */
6425 LOG(1, "Read kernel function: %s", filename);
6426
6427 /* Open file... */
6428 FILE *in;
6429 if (!(in = fopen(filename, "r")))
6430 ERRMSG("Cannot open file!");
6431
6432 /* Read data... */
6433 char line[LEN];
6434 int n = 0;
6435 while (fgets(line, LEN, in))
6436 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
6437 if (n > 0 && kz[n] < kz[n - 1])
6438 ERRMSG("Height levels must be ascending!");
6439 if ((++n) >= EP)
6440 ERRMSG("Too many height levels!");
6441 }
6442
6443 /* Close file... */
6444 fclose(in);
6445
6446 /* Check number of data points... */
6447 *nk = n;
6448 if (n < 2)
6449 ERRMSG("Not enough height levels!");
6450
6451 /* Normalize kernel function... */
6452 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
6453 for (int iz = 0; iz < n; iz++)
6454 kw[iz] /= kmax;
6455}

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

6462 {
6463
6464 FILE *in;
6465
6466 double r;
6467
6468 int year, mon, day, hour, min, sec;
6469
6470 /* Set timer... */
6471 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
6472
6473 /* Open file... */
6474 if (!(in = fopen(filename, "r"))) {
6475 WARN("Cannot open file!");
6476 return 0;
6477 }
6478
6479 /* Check type of binary data... */
6480 int met_type;
6481 FREAD(&met_type, int,
6482 1,
6483 in);
6484 if (met_type != ctl->met_type)
6485 ERRMSG("Wrong MET_TYPE of binary data!");
6486
6487 /* Check version of binary data... */
6488 int version;
6489 FREAD(&version, int,
6490 1,
6491 in);
6492 if (version != 103)
6493 ERRMSG("Wrong version of binary data!");
6494
6495 /* Read time... */
6496 FREAD(&met->time, double,
6497 1,
6498 in);
6499 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
6500 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
6501 met->time, year, mon, day, hour, min);
6502 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
6503 || day < 1 || day > 31 || hour < 0 || hour > 23)
6504 ERRMSG("Error while reading time!");
6505
6506 /* Read dimensions... */
6507 FREAD(&met->nx, int,
6508 1,
6509 in);
6510 LOG(2, "Number of longitudes: %d", met->nx);
6511 if (met->nx < 2 || met->nx > EX)
6512 ERRMSG("Number of longitudes out of range!");
6513
6514 FREAD(&met->ny, int,
6515 1,
6516 in);
6517 LOG(2, "Number of latitudes: %d", met->ny);
6518 if (met->ny < 2 || met->ny > EY)
6519 ERRMSG("Number of latitudes out of range!");
6520
6521 FREAD(&met->np, int,
6522 1,
6523 in);
6524 LOG(2, "Number of levels: %d", met->np);
6525 if (met->np < 2 || met->np > EP)
6526 ERRMSG("Number of levels out of range!");
6527
6528 /* Read grid... */
6529 FREAD(met->lon, double,
6530 (size_t) met->nx,
6531 in);
6532 LOG(2, "Longitudes: %g, %g ... %g deg",
6533 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
6534
6535 FREAD(met->lat, double,
6536 (size_t) met->ny,
6537 in);
6538 LOG(2, "Latitudes: %g, %g ... %g deg",
6539 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
6540
6541 FREAD(met->p, double,
6542 (size_t) met->np,
6543 in);
6544 LOG(2, "Altitude levels: %g, %g ... %g km",
6545 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
6546 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6547 met->p[0], met->p[1], met->p[met->np - 1]);
6548
6549 /* Read surface data... */
6550 read_met_bin_2d(in, met, met->ps, "PS");
6551 read_met_bin_2d(in, met, met->ts, "TS");
6552 read_met_bin_2d(in, met, met->zs, "ZS");
6553 read_met_bin_2d(in, met, met->us, "US");
6554 read_met_bin_2d(in, met, met->vs, "VS");
6555 read_met_bin_2d(in, met, met->ess, "ESS");
6556 read_met_bin_2d(in, met, met->nss, "NSS");
6557 read_met_bin_2d(in, met, met->shf, "SHF");
6558 read_met_bin_2d(in, met, met->lsm, "LSM");
6559 read_met_bin_2d(in, met, met->sst, "SST");
6560 read_met_bin_2d(in, met, met->pbl, "PBL");
6561 read_met_bin_2d(in, met, met->pt, "PT");
6562 read_met_bin_2d(in, met, met->tt, "TT");
6563 read_met_bin_2d(in, met, met->zt, "ZT");
6564 read_met_bin_2d(in, met, met->h2ot, "H2OT");
6565 read_met_bin_2d(in, met, met->pct, "PCT");
6566 read_met_bin_2d(in, met, met->pcb, "PCB");
6567 read_met_bin_2d(in, met, met->cl, "CL");
6568 read_met_bin_2d(in, met, met->plcl, "PLCL");
6569 read_met_bin_2d(in, met, met->plfc, "PLFC");
6570 read_met_bin_2d(in, met, met->pel, "PEL");
6571 read_met_bin_2d(in, met, met->cape, "CAPE");
6572 read_met_bin_2d(in, met, met->cin, "CIN");
6573 read_met_bin_2d(in, met, met->o3c, "O3C");
6574
6575 /* Read level data... */
6576 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
6577 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
6578 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
6579 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
6580 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
6581 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
6582 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
6583 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
6584 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
6585 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
6586 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
6587 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
6588 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
6589
6590 /* Read final flag... */
6591 int final;
6592 FREAD(&final, int,
6593 1,
6594 in);
6595 if (final != 999)
6596 ERRMSG("Error while reading binary data!");
6597
6598 /* Close file... */
6599 fclose(in);
6600
6601 /* Return success... */
6602 return 1;
6603}
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:6607
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:6636
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:282
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3459
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3447
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3519
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3489
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3483
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3465
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3441
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3516
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3429
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3528
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3423
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3435
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3468
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3480
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3486
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3474
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3456
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3450
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3432
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3444
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3522
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3462
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3507
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3471
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3438
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3477
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3525
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 6607 of file mptrac.c.

6611 {
6612
6613 float *help;
6614
6615 /* Allocate... */
6616 ALLOC(help, float,
6617 EX * EY);
6618
6619 /* Read uncompressed... */
6620 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
6621 FREAD(help, float,
6622 (size_t) (met->nx * met->ny),
6623 in);
6624
6625 /* Copy data... */
6626 for (int ix = 0; ix < met->nx; ix++)
6627 for (int iy = 0; iy < met->ny; iy++)
6628 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
6629
6630 /* Free... */
6631 free(help);
6632}
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:383

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

6643 {
6644
6645 float *help;
6646
6647 /* Allocate... */
6648 ALLOC(help, float,
6649 EX * EY * EP);
6650
6651 /* Read uncompressed data... */
6652 if (ctl->met_type == 1) {
6653 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
6654 FREAD(help, float,
6655 (size_t) (met->nx * met->ny * met->np),
6656 in);
6657 }
6658
6659 /* Read packed data... */
6660 else if (ctl->met_type == 2)
6661 compress_pck(varname, help, (size_t) (met->ny * met->nx),
6662 (size_t) met->np, 1, in);
6663
6664 /* Read zfp data... */
6665 else if (ctl->met_type == 3) {
6666#ifdef ZFP
6667 int precision;
6668 FREAD(&precision, int,
6669 1,
6670 in);
6671
6672 double tolerance;
6673 FREAD(&tolerance, double,
6674 1,
6675 in);
6676
6677 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
6678 tolerance, 1, in);
6679#else
6680 ERRMSG("MPTRAC was compiled without zfp compression!");
6681#endif
6682 }
6683
6684 /* Read zstd data... */
6685 else if (ctl->met_type == 4) {
6686#ifdef ZSTD
6687 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
6688 ctl->met_zstd_level, in);
6689#else
6690 ERRMSG("MPTRAC was compiled without zstd compression!");
6691#endif
6692 }
6693
6694 /* Read cmultiscale data... */
6695 else if (ctl->met_type == 5) {
6696#ifdef CMS
6697 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
6698 (size_t) met->np, 1, in);
6699#else
6700 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6701#endif
6702 }
6703
6704 /* Copy data... */
6705#pragma omp parallel for default(shared) collapse(2)
6706 for (int ix = 0; ix < met->nx; ix++)
6707 for (int iy = 0; iy < met->ny; iy++)
6708 for (int ip = 0; ip < met->np; ip++) {
6709 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
6710 if (var[ix][iy][ip] < bound_min)
6711 var[ix][iy][ip] = bound_min;
6712 else if (var[ix][iy][ip] > bound_max)
6713 var[ix][iy][ip] = bound_max;
6714 }
6715
6716 /* Free... */
6717 free(help);
6718}
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:706
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.
int met_zstd_level
ZSTD compression level (from -5 to 22).
Definition: mptrac.h:2509
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 6722 of file mptrac.c.

6725 {
6726
6727 /* Check parameters... */
6728 if (ctl->met_cape != 1)
6729 return;
6730
6731 /* Set timer... */
6732 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
6733 LOG(2, "Calculate CAPE...");
6734
6735 /* Vertical spacing (about 100 m)... */
6736 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
6737
6738 /* Loop over columns... */
6739#pragma omp parallel for default(shared) collapse(2)
6740 for (int ix = 0; ix < met->nx; ix++)
6741 for (int iy = 0; iy < met->ny; iy++) {
6742
6743 /* Get potential temperature and water vapor at lowest 50 hPa... */
6744 int n = 0;
6745 double h2o = 0, t, theta = 0;
6746 double pbot = MIN(met->ps[ix][iy], met->p[0]);
6747 double ptop = pbot - 50.;
6748 for (int ip = 0; ip < met->np; ip++) {
6749 if (met->p[ip] <= pbot) {
6750 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
6751 h2o += met->h2o[ix][iy][ip];
6752 n++;
6753 }
6754 if (met->p[ip] < ptop && n > 0)
6755 break;
6756 }
6757 theta /= n;
6758 h2o /= n;
6759
6760 /* Cannot compute anything if water vapor is missing... */
6761 met->plcl[ix][iy] = NAN;
6762 met->plfc[ix][iy] = NAN;
6763 met->pel[ix][iy] = NAN;
6764 met->cape[ix][iy] = NAN;
6765 met->cin[ix][iy] = NAN;
6766 if (h2o <= 0)
6767 continue;
6768
6769 /* Find lifted condensation level (LCL)... */
6770 ptop = P(20.);
6771 pbot = met->ps[ix][iy];
6772 do {
6773 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
6774 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
6775 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
6776 ptop = met->plcl[ix][iy];
6777 else
6778 pbot = met->plcl[ix][iy];
6779 } while (pbot - ptop > 0.1);
6780
6781 /* Calculate CIN up to LCL... */
6783 double dcape, dz, h2o_env, t_env;
6784 double p = met->ps[ix][iy];
6785 met->cape[ix][iy] = met->cin[ix][iy] = 0;
6786 do {
6787 dz = dz0 * TVIRT(t, h2o);
6788 p /= pfac;
6789 t = theta / pow(1000. / p, 0.286);
6790 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6791 &t_env, ci, cw, 1);
6792 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6793 &h2o_env, ci, cw, 0);
6794 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6795 TVIRT(t_env, h2o_env) * dz;
6796 if (dcape < 0)
6797 met->cin[ix][iy] += fabsf((float) dcape);
6798 } while (p > met->plcl[ix][iy]);
6799
6800 /* Calculate level of free convection (LFC), equilibrium level (EL),
6801 and convective available potential energy (CAPE)... */
6802 dcape = 0;
6803 p = met->plcl[ix][iy];
6804 t = theta / pow(1000. / p, 0.286);
6805 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
6806 do {
6807 dz = dz0 * TVIRT(t, h2o);
6808 p /= pfac;
6809 t -= lapse_rate(t, h2o) * dz;
6810 double psat = PSAT(t);
6811 h2o = psat / (p - (1. - EPS) * psat);
6812 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6813 &t_env, ci, cw, 1);
6814 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6815 &h2o_env, ci, cw, 0);
6816 double dcape_old = dcape;
6817 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6818 TVIRT(t_env, h2o_env) * dz;
6819 if (dcape > 0) {
6820 met->cape[ix][iy] += (float) dcape;
6821 if (!isfinite(met->plfc[ix][iy]))
6822 met->plfc[ix][iy] = (float) p;
6823 } else if (dcape_old > 0)
6824 met->pel[ix][iy] = (float) p;
6825 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
6826 met->cin[ix][iy] += fabsf((float) dcape);
6827 } while (p > ptop);
6828
6829 /* Check results... */
6830 if (!isfinite(met->plfc[ix][iy]))
6831 met->cin[ix][iy] = NAN;
6832 }
6833}
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:200
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 6837 of file mptrac.c.

6838 {
6839
6840 /* Set timer... */
6841 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
6842 LOG(2, "Calculate cloud data...");
6843
6844 /* Thresholds for cloud detection... */
6845 const double ccmin = 0.01, cwmin = 1e-6;
6846
6847 /* Loop over columns... */
6848#pragma omp parallel for default(shared) collapse(2)
6849 for (int ix = 0; ix < met->nx; ix++)
6850 for (int iy = 0; iy < met->ny; iy++) {
6851
6852 /* Init... */
6853 met->pct[ix][iy] = NAN;
6854 met->pcb[ix][iy] = NAN;
6855 met->cl[ix][iy] = 0;
6856
6857 /* Loop over pressure levels... */
6858 for (int ip = 0; ip < met->np - 1; ip++) {
6859
6860 /* Check pressure... */
6861 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
6862 continue;
6863
6864 /* Check ice water and liquid water content... */
6865 if (met->cc[ix][iy][ip] > ccmin
6866 && (met->lwc[ix][iy][ip] > cwmin
6867 || met->rwc[ix][iy][ip] > cwmin
6868 || met->iwc[ix][iy][ip] > cwmin
6869 || met->swc[ix][iy][ip] > cwmin)) {
6870
6871 /* Get cloud top pressure ... */
6872 met->pct[ix][iy]
6873 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
6874
6875 /* Get cloud bottom pressure ... */
6876 if (!isfinite(met->pcb[ix][iy]))
6877 met->pcb[ix][iy]
6878 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
6879 }
6880
6881 /* Get cloud water... */
6882 met->cl[ix][iy] += (float)
6883 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
6884 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
6885 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
6886 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
6887 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
6888 }
6889 }
6890}

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

6896 {
6897
6898 met_t *help;
6899
6900 /* Check parameters... */
6901 if (ctl->met_detrend <= 0)
6902 return;
6903
6904 /* Set timer... */
6905 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
6906 LOG(2, "Detrend meteo data...");
6907
6908 /* Allocate... */
6909 ALLOC(help, met_t, 1);
6910
6911 /* Calculate standard deviation... */
6912 const double sigma = ctl->met_detrend / 2.355;
6913 const double tssq = 2. * SQR(sigma);
6914
6915 /* Calculate box size in latitude... */
6916 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
6917 sy = MIN(MAX(1, sy), met->ny / 2);
6918
6919 /* Calculate background... */
6920#pragma omp parallel for default(shared) collapse(2)
6921 for (int ix = 0; ix < met->nx; ix++) {
6922 for (int iy = 0; iy < met->ny; iy++) {
6923
6924 /* Calculate Cartesian coordinates... */
6925 double x0[3];
6926 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
6927
6928 /* Calculate box size in longitude... */
6929 int sx =
6930 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
6931 fabs(met->lon[1] - met->lon[0]));
6932 sx = MIN(MAX(1, sx), met->nx / 2);
6933
6934 /* Init... */
6935 float wsum = 0;
6936 for (int ip = 0; ip < met->np; ip++) {
6937 help->t[ix][iy][ip] = 0;
6938 help->u[ix][iy][ip] = 0;
6939 help->v[ix][iy][ip] = 0;
6940 help->w[ix][iy][ip] = 0;
6941 }
6942
6943 /* Loop over neighboring grid points... */
6944 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
6945 int ix3 = ix2;
6946 if (ix3 < 0)
6947 ix3 += met->nx;
6948 else if (ix3 >= met->nx)
6949 ix3 -= met->nx;
6950 for (int iy2 = MAX(iy - sy, 0);
6951 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
6952
6953 /* Calculate Cartesian coordinates... */
6954 double x1[3];
6955 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
6956
6957 /* Calculate weighting factor... */
6958 const float w = (float) exp(-DIST2(x0, x1) / tssq);
6959
6960 /* Add data... */
6961 wsum += w;
6962 for (int ip = 0; ip < met->np; ip++) {
6963 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
6964 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
6965 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
6966 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
6967 }
6968 }
6969 }
6970
6971 /* Normalize... */
6972 for (int ip = 0; ip < met->np; ip++) {
6973 help->t[ix][iy][ip] /= wsum;
6974 help->u[ix][iy][ip] /= wsum;
6975 help->v[ix][iy][ip] /= wsum;
6976 help->w[ix][iy][ip] /= wsum;
6977 }
6978 }
6979 }
6980
6981 /* Subtract background... */
6982#pragma omp parallel for default(shared) collapse(3)
6983 for (int ix = 0; ix < met->nx; ix++)
6984 for (int iy = 0; iy < met->ny; iy++)
6985 for (int ip = 0; ip < met->np; ip++) {
6986 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
6987 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
6988 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
6989 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
6990 }
6991
6992 /* Free... */
6993 free(help);
6994}
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:1030
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:605
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2588
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 6998 of file mptrac.c.

6999 {
7000
7001 /* Set timer... */
7002 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
7003 LOG(2, "Extrapolate meteo data...");
7004
7005 /* Loop over columns... */
7006#pragma omp parallel for default(shared) collapse(2)
7007 for (int ix = 0; ix < met->nx; ix++)
7008 for (int iy = 0; iy < met->ny; iy++) {
7009
7010 /* Find lowest valid data point... */
7011 int ip0;
7012 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
7013 if (!isfinite(met->t[ix][iy][ip0])
7014 || !isfinite(met->u[ix][iy][ip0])
7015 || !isfinite(met->v[ix][iy][ip0])
7016 || !isfinite(met->w[ix][iy][ip0]))
7017 break;
7018
7019 /* Extrapolate... */
7020 for (int ip = ip0; ip >= 0; ip--) {
7021 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
7022 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
7023 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
7024 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
7025 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
7026 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
7027 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
7028 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
7029 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
7030 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
7031 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
7032 }
7033 }
7034}

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

7040 {
7041
7042 float *help;
7043
7044 double logp[EP];
7045
7046 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
7047
7048 /* Set timer... */
7049 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
7050 LOG(2, "Calculate geopotential heights...");
7051
7052 /* Allocate... */
7053 ALLOC(help, float,
7054 EX * EY * EP);
7055
7056 /* Calculate log pressure... */
7057#pragma omp parallel for default(shared)
7058 for (int ip = 0; ip < met->np; ip++)
7059 logp[ip] = log(met->p[ip]);
7060
7061 /* Apply hydrostatic equation to calculate geopotential heights... */
7062#pragma omp parallel for default(shared) collapse(2)
7063 for (int ix = 0; ix < met->nx; ix++)
7064 for (int iy = 0; iy < met->ny; iy++) {
7065
7066 /* Get surface height and pressure... */
7067 const double zs = met->zs[ix][iy];
7068 const double lnps = log(met->ps[ix][iy]);
7069
7070 /* Get temperature and water vapor at the surface... */
7071 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
7072 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
7073 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
7074 const double h2os =
7075 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
7076 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
7077
7078 /* Upper part of profile... */
7079 met->z[ix][iy][ip0 + 1]
7080 = (float) (zs +
7081 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
7082 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
7083 for (int ip = ip0 + 2; ip < met->np; ip++)
7084 met->z[ix][iy][ip]
7085 = (float) (met->z[ix][iy][ip - 1] +
7086 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
7087 met->h2o[ix][iy][ip - 1], logp[ip],
7088 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7089
7090 /* Lower part of profile... */
7091 met->z[ix][iy][ip0]
7092 = (float) (zs +
7093 ZDIFF(lnps, ts, h2os, logp[ip0],
7094 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
7095 for (int ip = ip0 - 1; ip >= 0; ip--)
7096 met->z[ix][iy][ip]
7097 = (float) (met->z[ix][iy][ip + 1] +
7098 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
7099 met->h2o[ix][iy][ip + 1], logp[ip],
7100 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7101 }
7102
7103 /* Check control parameters... */
7104 if (dx == 0 || dy == 0)
7105 return;
7106
7107 /* Default smoothing parameters... */
7108 if (dx < 0 || dy < 0) {
7109 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
7110 dx = 3;
7111 dy = 2;
7112 } else {
7113 dx = 6;
7114 dy = 4;
7115 }
7116 }
7117
7118 /* Calculate weights for smoothing... */
7119 float ws[dx + 1][dy + 1];
7120#pragma omp parallel for default(shared) collapse(2)
7121 for (int ix = 0; ix <= dx; ix++)
7122 for (int iy = 0; iy < dy; iy++)
7123 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
7124 * (1.0f - (float) iy / (float) dy);
7125
7126 /* Copy data... */
7127#pragma omp parallel for default(shared) collapse(3)
7128 for (int ix = 0; ix < met->nx; ix++)
7129 for (int iy = 0; iy < met->ny; iy++)
7130 for (int ip = 0; ip < met->np; ip++)
7131 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
7132
7133 /* Horizontal smoothing... */
7134#pragma omp parallel for default(shared) collapse(3)
7135 for (int ip = 0; ip < met->np; ip++)
7136 for (int ix = 0; ix < met->nx; ix++)
7137 for (int iy = 0; iy < met->ny; iy++) {
7138 float res = 0, wsum = 0;
7139 int iy0 = MAX(iy - dy + 1, 0);
7140 int iy1 = MIN(iy + dy - 1, met->ny - 1);
7141 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
7142 int ix3 = ix2;
7143 if (ix3 < 0)
7144 ix3 += met->nx;
7145 else if (ix3 >= met->nx)
7146 ix3 -= met->nx;
7147 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
7148 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
7149 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
7150 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
7151 wsum += w;
7152 }
7153 }
7154 if (wsum > 0)
7155 met->z[ix][iy][ip] = res / wsum;
7156 else
7157 met->z[ix][iy][ip] = NAN;
7158 }
7159
7160 /* Free... */
7161 free(help);
7162}
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1783
Here is the call graph for this function:

◆ read_met_grid()

void read_met_grid ( const char *  filename,
const int  ncid,
const ctl_t ctl,
met_t met 
)

Reads meteorological grid information from a NetCDF file.

This function reads meteorological grid information from a NetCDF file, including time, spatial dimensions, and pressure levels. It also extracts longitudes, latitudes, and pressure levels from the NetCDF file based on the specified control parameters. The function determines the time information either from the filename or from the data file, depending on the file type.

Parameters
filenameThe filename of the NetCDF file.
ncidThe NetCDF file identifier.
ctlA pointer to a structure containing control parameters.
metA pointer to a structure to store meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the reading time for meteorological grid information.
  • Determines the time information from either the filename or the data file based on the file type.
  • Checks the validity of the time information.
  • Retrieves grid dimensions (longitude, latitude, and vertical levels) from the NetCDF file.
  • Reads longitudes, latitudes, and pressure levels from the NetCDF file.
  • Converts pressure levels to hPa if necessary.
  • Logs the retrieved grid information for verification and debugging purposes.
Note
This function supports reading meteorological grid information from different types of NetCDF files, including MPTRAC and CLaMS. The time information is extracted either from the filename or from the data file, depending on the file type and control parameters. Spatial dimensions (longitude, latitude, and vertical levels) and pressure levels are retrieved from the NetCDF file.
Authors
Lars Hoffmann
Jan Clemens

Definition at line 7166 of file mptrac.c.

7170 {
7171
7172 char levname[LEN], tstr[10];
7173
7174 double rtime = 0, r, r2;
7175
7176 int varid, year2, mon2, day2, hour2, min2, sec2,
7177 year, mon, day, hour, min, sec;
7178
7179 size_t np;
7180
7181 /* Set timer... */
7182 SELECT_TIMER("READ_MET_GRID", "INPUT", NVTX_READ);
7183 LOG(2, "Read meteo grid information...");
7184
7185 /* MPTRAC meteo files... */
7186 if (ctl->met_clams == 0) {
7187
7188 /* Get time from filename... */
7189 met->time = time_from_filename(filename, 16);
7190
7191 /* Check time information from data file... */
7192 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7193 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
7194 NC(nc_get_var_double(ncid, varid, &rtime));
7195 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
7196 WARN("Time information in meteo file does not match filename!");
7197 } else
7198 WARN("Time information in meteo file is missing!");
7199 }
7200
7201 /* CLaMS meteo files... */
7202 else {
7203
7204 /* Read time from file... */
7205 NC_GET_DOUBLE("time", &rtime, 0);
7206
7207 /* Get time from filename (considering the century)... */
7208 if (rtime < 0)
7209 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
7210 else
7211 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
7212 year = atoi(tstr);
7213 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
7214 mon = atoi(tstr);
7215 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
7216 day = atoi(tstr);
7217 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
7218 hour = atoi(tstr);
7219 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
7220 }
7221
7222 /* Check time... */
7223 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7224 || day < 1 || day > 31 || hour < 0 || hour > 23)
7225 ERRMSG("Cannot read time from filename!");
7226 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
7227 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7228 met->time, year2, mon2, day2, hour2, min2);
7229
7230 /* Get grid dimensions... */
7231 NC_INQ_DIM("lon", &met->nx, 2, EX);
7232 LOG(2, "Number of longitudes: %d", met->nx);
7233
7234 NC_INQ_DIM("lat", &met->ny, 2, EY);
7235 LOG(2, "Number of latitudes: %d", met->ny);
7236
7237 int dimid2;
7238 sprintf(levname, "lev");
7239 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7240 sprintf(levname, "plev");
7241 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7242 sprintf(levname, "hybrid");
7243 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7244 sprintf(levname, "hybrid_level");
7245
7246 NC_INQ_DIM(levname, &met->np, 1, EP);
7247 if (met->np == 1) {
7248 sprintf(levname, "lev_2");
7249 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR) {
7250 sprintf(levname, "plev");
7251 NC(nc_inq_dimid(ncid, levname, &dimid2));
7252 }
7253 NC(nc_inq_dimlen(ncid, dimid2, &np));
7254 met->np = (int) np;
7255 }
7256 LOG(2, "Number of levels: %d", met->np);
7257 if (met->np < 2 || met->np > EP)
7258 ERRMSG("Number of levels out of range!");
7259
7260 /* Read longitudes and latitudes... */
7261 NC_GET_DOUBLE("lon", met->lon, 1);
7262 LOG(2, "Longitudes: %g, %g ... %g deg",
7263 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7264 NC_GET_DOUBLE("lat", met->lat, 1);
7265 LOG(2, "Latitudes: %g, %g ... %g deg",
7266 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7267
7268 /* Check grid spacing... */
7269 for (int ix = 2; ix < met->nx; ix++)
7270 if (fabs
7271 (fabs(met->lon[ix] - met->lon[ix - 1]) -
7272 fabs(met->lon[1] - met->lon[0])) > 0.001)
7273 ERRMSG("No regular grid spacing in longitudes!");
7274 for (int iy = 2; iy < met->ny; iy++)
7275 if (fabs
7276 (fabs(met->lat[iy] - met->lat[iy - 1]) -
7277 fabs(met->lat[1] - met->lat[0])) > 0.001) {
7278 WARN("No regular grid spacing in latitudes!");
7279 break;
7280 }
7281
7282 /* Read pressure levels... */
7283 if (ctl->met_np <= 0) {
7284 NC_GET_DOUBLE(levname, met->p, 1);
7285 for (int ip = 0; ip < met->np; ip++)
7286 met->p[ip] /= 100.;
7287 LOG(2, "Altitude levels: %g, %g ... %g km",
7288 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7289 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7290 met->p[0], met->p[1], met->p[met->np - 1]);
7291 }
7292
7293 /* Read hybrid levels... */
7294 if (strcasecmp(levname, "hybrid") == 0)
7295 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
7296}
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:9203
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:9302
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3417
Here is the call graph for this function:

◆ read_met_levels()

void read_met_levels ( const int  ncid,
const ctl_t ctl,
met_t met 
)

Reads meteorological variables at different vertical levels from a NetCDF file.

This function reads meteorological variables such as temperature, wind components, specific humidity, ozone data, cloud parameters, and cloud cover at various vertical levels from a NetCDF file. The function supports reading meteorological data from both MPTRAC and CLaMS formats. Depending on the file format, it reads specific variables and performs necessary conversions or interpolations.

Parameters
ncidThe NetCDF file identifier.
ctlA pointer to a structure containing control parameters.
metA pointer to a structure to store meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the reading time for meteorological level data.
  • Reads meteorological variables from the NetCDF file based on the specified control parameters and file format.
  • Handles specific variables differently depending on the file format, such as reading temperature, wind components, humidity, ozone data, and cloud parameters.
  • Performs conversions or interpolations if necessary, such as converting specific humidity and ozone data from mixing ratio to volume mixing ratio.
  • Transfers velocity components to model levels for diabatic advection if applicable.
  • Reads pressure on model levels if specified in the control parameters.
  • Performs vertical interpolation from model levels to pressure levels if needed.
  • Checks the ordering of pressure levels to ensure they are in descending order.
Note
This function supports reading meteorological variables from NetCDF files in MPTRAC or CLaMS formats and handles specific variables differently based on the file format and control parameters. It performs necessary conversions or interpolations and ensures the correctness of pressure levels.
Authors
Lars Hoffmann
Jan Clemens

Definition at line 7300 of file mptrac.c.

7303 {
7304
7305 /* Set timer... */
7306 SELECT_TIMER("READ_MET_LEVELS", "INPUT", NVTX_READ);
7307 LOG(2, "Read level data...");
7308
7309 /* Read temperature... */
7310 if (!read_met_nc_3d(ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
7311 ERRMSG("Cannot read temperature!");
7312
7313 /* Read horizontal wind and vertical velocity... */
7314 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
7315 ERRMSG("Cannot read zonal wind!");
7316 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
7317 ERRMSG("Cannot read meridional wind!");
7318 if (!read_met_nc_3d
7319 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
7320 WARN("Cannot read vertical velocity!");
7321
7322 /* Read water vapor... */
7323 if (!ctl->met_relhum) {
7324 if (!read_met_nc_3d
7325 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
7326 WARN("Cannot read specific humidity!");
7327 } else {
7328 if (!read_met_nc_3d
7329 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
7330 WARN("Cannot read relative humidity!");
7331#pragma omp parallel for default(shared) collapse(2)
7332 for (int ix = 0; ix < met->nx; ix++)
7333 for (int iy = 0; iy < met->ny; iy++)
7334 for (int ip = 0; ip < met->np; ip++) {
7335 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
7336 met->h2o[ix][iy][ip] =
7337 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
7338 }
7339 }
7340
7341 /* Read ozone... */
7342 if (!read_met_nc_3d
7343 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
7344 WARN("Cannot read ozone data!");
7345
7346 /* Read cloud data... */
7347 if (!read_met_nc_3d
7348 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
7349 WARN("Cannot read cloud liquid water content!");
7350 if (!read_met_nc_3d
7351 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
7352 WARN("Cannot read cloud rain water content!");
7353 if (!read_met_nc_3d
7354 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
7355 WARN("Cannot read cloud ice water content!");
7356 if (!read_met_nc_3d
7357 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
7358 WARN("Cannot read cloud snow water content!");
7359 if (!read_met_nc_3d(ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
7360 WARN("Cannot read cloud cover!");
7361
7362 /* Read zeta and zeta_dot... */
7363 if (!read_met_nc_3d
7364 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
7365 WARN("Cannot read ZETA!");
7366 if (!read_met_nc_3d
7367 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
7368 NULL, ctl, met, met->zeta_dotl, 0.00001157407f))
7369 WARN("Cannot read ZETA_DOT!");
7370
7371 /* Store velocities on model levels... */
7372 if (ctl->met_vert_coord != 0) {
7373 for (int ix = 0; ix < met->nx; ix++)
7374 for (int iy = 0; iy < met->ny; iy++)
7375 for (int ip = 0; ip < met->np; ip++) {
7376 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
7377 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
7378 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
7379 }
7380
7381 /* Save number of model levels... */
7382 met->npl = met->np;
7383 }
7384
7385 /* Get pressure on model levels... */
7386 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
7387
7388 /* Read 3-D pressure field... */
7389 if (ctl->met_vert_coord == 1) {
7390 if (!read_met_nc_3d
7391 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl,
7392 0.01f))
7393 if (!read_met_nc_3d
7394 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
7395 ERRMSG("Cannot read pressure on model levels!");
7396 }
7397
7398 /* Use a and b coefficients for full levels... */
7399 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
7400
7401 /* Grid level coefficients... */
7402 double hyam[EP], hybm[EP];
7403
7404 /* Read coefficients from file... */
7405 if (ctl->met_vert_coord == 2) {
7406 int varid;
7407 if (nc_inq_varid(ncid, "hyam", &varid) == NC_NOERR
7408 && nc_inq_varid(ncid, "hybm", &varid) == NC_NOERR) {
7409 NC_GET_DOUBLE("hyam", hyam, 1);
7410 NC_GET_DOUBLE("hybm", hybm, 1);
7411 } else if (nc_inq_varid(ncid, "a_hybrid_level", &varid) == NC_NOERR
7412 && nc_inq_varid(ncid, "b_hybrid_level",
7413 &varid) == NC_NOERR) {
7414 NC_GET_DOUBLE("a_hybrid_level", hyam, 1);
7415 NC_GET_DOUBLE("b_hybrid_level", hybm, 1);
7416 } else
7417 ERRMSG("Cannot read a and b level coefficients from netCDF file!");
7418 }
7419
7420 /* Use control parameters... */
7421 else if (ctl->met_vert_coord == 3) {
7422
7423 /* Check number of levels... */
7424 if (met->np != ctl->met_nlev)
7425 ERRMSG("Mismatch in number of model levels!");
7426
7427 /* Copy parameters... */
7428 for (int ip = 0; ip < met->np; ip++) {
7429 hyam[ip] = ctl->met_lev_hyam[ip];
7430 hybm[ip] = ctl->met_lev_hybm[ip];
7431 }
7432 }
7433
7434 /* Calculate pressure... */
7435 for (int ix = 0; ix < met->nx; ix++)
7436 for (int iy = 0; iy < met->ny; iy++)
7437 for (int ip = 0; ip < met->np; ip++)
7438 met->pl[ix][iy][ip] =
7439 (float) (hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy]);
7440 }
7441
7442 /* Use a and b coefficients for half levels... */
7443 else if (ctl->met_vert_coord == 4) {
7444
7445 /* Grid level coefficients... */
7446 double hyam[EP], hybm[EP];
7447
7448 /* Use control parameters... */
7449 for (int ip = 0; ip < met->np + 1; ip++) {
7450 hyam[ip] = ctl->met_lev_hyam[ip];
7451 hybm[ip] = ctl->met_lev_hybm[ip];
7452 }
7453
7454 /* Check number of levels... */
7455 if (met->np + 1 != ctl->met_nlev)
7456 ERRMSG("Mismatch in number of model levels!");
7457
7458 /* Calculate pressure... */
7459#pragma omp parallel for default(shared) collapse(2)
7460 for (int ix = 0; ix < met->nx; ix++)
7461 for (int iy = 0; iy < met->ny; iy++)
7462 for (int ip = 0; ip < met->np; ip++) {
7463 double p0 = hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy];
7464 double p1 = hyam[ip + 1] / 100. + hybm[ip + 1] * met->ps[ix][iy];
7465 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
7466 }
7467 }
7468
7469 /* Check ordering of pressure levels... */
7470 for (int ix = 0; ix < met->nx; ix++)
7471 for (int iy = 0; iy < met->ny; iy++)
7472 for (int ip = 1; ip < met->np; ip++)
7473 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
7474 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
7475 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
7476 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
7477 ERRMSG("Pressure profiles are not monotonic!");
7478 }
7479
7480 /* Interpolate from model levels to pressure levels... */
7481 if (ctl->met_np > 0) {
7482
7483 /* Check pressure on model levels... */
7484 if (met->pl[0][0][0] <= 0)
7485 ERRMSG("Pressure on model levels is missing, check MET_VERT_COORD!");
7486
7487 /* Interpolate variables... */
7488 read_met_ml2pl(ctl, met, met->t, "T");
7489 read_met_ml2pl(ctl, met, met->u, "U");
7490 read_met_ml2pl(ctl, met, met->v, "V");
7491 read_met_ml2pl(ctl, met, met->w, "W");
7492 read_met_ml2pl(ctl, met, met->h2o, "H2O");
7493 read_met_ml2pl(ctl, met, met->o3, "O3");
7494 read_met_ml2pl(ctl, met, met->lwc, "LWC");
7495 read_met_ml2pl(ctl, met, met->rwc, "RWC");
7496 read_met_ml2pl(ctl, met, met->iwc, "IWC");
7497 read_met_ml2pl(ctl, met, met->swc, "SWC");
7498 read_met_ml2pl(ctl, met, met->cc, "CC");
7499
7500 /* Set new pressure levels... */
7501 met->np = ctl->met_np;
7502 for (int ip = 0; ip < met->np; ip++)
7503 met->p[ip] = ctl->met_p[ip];
7504 }
7505
7506 /* Check ordering of pressure levels... */
7507 for (int ip = 1; ip < met->np; ip++)
7508 if (met->p[ip - 1] < met->p[ip])
7509 ERRMSG("Pressure levels must be descending!");
7510}
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:7514
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, float dest[EX][EY][EP], const float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:7870
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:213
#define MO3
Molar mass of ozone [g/mol].
Definition: mptrac.h:218
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:2490
Here is the call graph for this function:

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

7518 {
7519
7520 double aux[EP], p[EP];
7521
7522 /* Set timer... */
7523 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
7524 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
7525
7526 /* Loop over columns... */
7527#pragma omp parallel for default(shared) private(aux,p) collapse(2)
7528 for (int ix = 0; ix < met->nx; ix++)
7529 for (int iy = 0; iy < met->ny; iy++) {
7530
7531 /* Copy pressure profile... */
7532 for (int ip = 0; ip < met->np; ip++)
7533 p[ip] = met->pl[ix][iy][ip];
7534
7535 /* Interpolate... */
7536 for (int ip = 0; ip < ctl->met_np; ip++) {
7537 double pt = ctl->met_p[ip];
7538 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
7539 pt = p[0];
7540 else if ((pt > p[met->np - 1] && p[1] > p[0])
7541 || (pt < p[met->np - 1] && p[1] < p[0]))
7542 pt = p[met->np - 1];
7543 int ip2 = locate_irr(p, met->np, pt);
7544 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
7545 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
7546 }
7547
7548 /* Copy data... */
7549 for (int ip = 0; ip < ctl->met_np; ip++)
7550 var[ix][iy][ip] = (float) aux[ip];
7551 }
7552}
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 7556 of file mptrac.c.

7558 {
7559
7560 /* Check parameters... */
7561 if (ctl->advect_vert_coord != 1)
7562 return;
7563
7564 /* Set timer... */
7565 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
7566 LOG(2, "Make zeta profiles monotone...");
7567
7568 /* Create monotone zeta profiles... */
7569#pragma omp parallel for default(shared) collapse(2)
7570 for (int i = 0; i < met->nx; i++)
7571 for (int j = 0; j < met->ny; j++) {
7572 int k = 1;
7573
7574 while (k < met->npl) { /* Check if there is an inversion at level k... */
7575 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
7576 /* Find the upper level k+l over the inversion... */
7577 int l = 0;
7578 do {
7579 l++;
7580 }
7581 while ((met->zetal[i][j][k - 1] >=
7582 met->zetal[i][j][k + l]) & (k + l < met->npl));
7583
7584 /* Interpolate linear between the top and bottom
7585 of the inversion... */
7586 float s =
7587 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
7588 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
7589
7590 for (int m = k; m < k + l; m++) {
7591 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
7592 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
7593 }
7594
7595 /* Search for more inversions above the last inversion ... */
7596 k = k + l;
7597 } else {
7598 k++;
7599 }
7600 }
7601 }
7602
7603 /* Create monotone pressure profiles... */
7604#pragma omp parallel for default(shared) collapse(2)
7605 for (int i = 0; i < met->nx; i++)
7606 for (int j = 0; j < met->ny; j++) {
7607 int k = 1;
7608
7609 while (k < met->npl) { /* Check if there is an inversion at level k... */
7610 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
7611
7612 /* Find the upper level k+l over the inversion... */
7613 int l = 0;
7614 do {
7615 l++;
7616 }
7617 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
7618 met->npl));
7619
7620 /* Interpolate linear between the top and bottom
7621 of the inversion... */
7622 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
7623 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
7624
7625 for (int m = k; m < k + l; m++) {
7626 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
7627 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
7628 }
7629
7630 /* Search for more inversions above the last inversion ... */
7631 k += l;
7632 } else {
7633 k++;
7634 }
7635 }
7636 }
7637}

◆ read_met_nc()

int read_met_nc ( const char *  filename,
const ctl_t ctl,
const clim_t clim,
met_t met 
)

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.
climA pointer to a clim_t structure that holds climatological data, used in the calculation of derived properties such as CAPE and tropopause 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 7641 of file mptrac.c.

7645 {
7646
7647 int ncid;
7648
7649 /* Open netCDF file... */
7650 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7651 WARN("Cannot open file!");
7652 return 0;
7653 }
7654
7655 /* Read coordinates of meteo data... */
7656 read_met_grid(filename, ncid, ctl, met);
7657
7658 /* Read surface data... */
7659 read_met_surface(ncid, ctl, met);
7660
7661 /* Read meteo data on vertical levels... */
7662 read_met_levels(ncid, ctl, met);
7663
7664 /* Extrapolate data for lower boundary... */
7666
7667 /* Fix polar winds... */
7669
7670 /* Create periodic boundary conditions... */
7671 read_met_periodic(met);
7672
7673 /* Downsampling... */
7674 read_met_sample(ctl, met);
7675
7676 /* Calculate geopotential heights... */
7677 read_met_geopot(ctl, met);
7678
7679 /* Calculate potential vorticity... */
7680 read_met_pv(met);
7681
7682 /* Calculate boundary layer data... */
7683 read_met_pbl(ctl, met);
7684
7685 /* Calculate tropopause data... */
7686 read_met_tropo(ctl, clim, met);
7687
7688 /* Calculate cloud properties... */
7689 read_met_cloud(met);
7690
7691 /* Calculate convective available potential energy... */
7692 read_met_cape(ctl, clim, met);
7693
7694 /* Calculate total column ozone... */
7695 read_met_ozone(met);
7696
7697 /* Detrending... */
7698 read_met_detrend(ctl, met);
7699
7700 /* Check meteo data and smooth zeta profiles ... */
7701 read_met_monotonize(ctl, met);
7702
7703 /* Close file... */
7704 NC(nc_close(ncid));
7705
7706 /* Return success... */
7707 return 1;
7708}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:7038
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:6998
void read_met_levels(const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological variables at different vertical levels from a NetCDF file.
Definition: mptrac.c:7300
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:8408
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:6837
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:8016
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:6894
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:7556
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:8153
void read_met_grid(const char *filename, const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological grid information from a NetCDF file.
Definition: mptrac.c:7166
void read_met_surface(const int ncid, const ctl_t *ctl, met_t *met)
Reads surface meteorological data from a netCDF file and stores it in the meteorological data structu...
Definition: mptrac.c:8580
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:8379
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:8273
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:8214
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:6722
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,
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 7712 of file mptrac.c.

7724 {
7725
7726 char varsel[LEN];
7727
7728 float offset, scalfac;
7729
7730 int varid;
7731
7732 /* Check if variable exists... */
7733 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7734 sprintf(varsel, "%s", varname);
7735 else if (varname2 != NULL
7736 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7737 sprintf(varsel, "%s", varname2);
7738 else if (varname3 != NULL
7739 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7740 sprintf(varsel, "%s", varname3);
7741 else if (varname4 != NULL
7742 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7743 sprintf(varsel, "%s", varname4);
7744 else if (varname5 != NULL
7745 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
7746 sprintf(varsel, "%s", varname5);
7747 else if (varname6 != NULL
7748 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
7749 sprintf(varsel, "%s", varname6);
7750 else
7751 return 0;
7752
7753 /* Read packed data... */
7754 if (ctl->met_nc_scale
7755 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7756 && nc_get_att_float(ncid, varid, "scale_factor",
7757 &scalfac) == NC_NOERR) {
7758
7759 /* Allocate... */
7760 short *help;
7761 ALLOC(help, short,
7762 EX * EY * EP);
7763
7764 /* Read fill value and missing value... */
7765 short fillval, missval;
7766 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7767 fillval = 0;
7768 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7769 missval = 0;
7770
7771 /* Write info... */
7772 LOG(2, "Read 2-D variable: %s"
7773 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7774 varsel, fillval, missval, scalfac, offset);
7775
7776 /* Read data... */
7777 NC(nc_get_var_short(ncid, varid, help));
7778
7779 /* Check meteo data layout... */
7780 if (ctl->met_convention != 0)
7781 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7782
7783 /* Copy and check data... */
7784#pragma omp parallel for default(shared) num_threads(12)
7785 for (int ix = 0; ix < met->nx; ix++)
7786 for (int iy = 0; iy < met->ny; iy++) {
7787 if (init)
7788 dest[ix][iy] = 0;
7789 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
7790 if ((fillval == 0 || aux != fillval)
7791 && (missval == 0 || aux != missval)
7792 && fabsf(aux * scalfac + offset) < 1e14f)
7793 dest[ix][iy] += scl * (aux * scalfac + offset);
7794 else
7795 dest[ix][iy] = NAN;
7796 }
7797
7798 /* Free... */
7799 free(help);
7800 }
7801
7802 /* Unpacked data... */
7803 else {
7804
7805 /* Allocate... */
7806 float *help;
7807 ALLOC(help, float,
7808 EX * EY);
7809
7810 /* Read fill value and missing value... */
7811 float fillval, missval;
7812 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7813 fillval = 0;
7814 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7815 missval = 0;
7816
7817 /* Write info... */
7818 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
7819 varsel, fillval, missval);
7820
7821 /* Read data... */
7822 NC(nc_get_var_float(ncid, varid, help));
7823
7824 /* Check meteo data layout... */
7825 if (ctl->met_convention == 0) {
7826
7827 /* Copy and check data (ordering: lat, lon)... */
7828#pragma omp parallel for default(shared) num_threads(12)
7829 for (int ix = 0; ix < met->nx; ix++)
7830 for (int iy = 0; iy < met->ny; iy++) {
7831 if (init)
7832 dest[ix][iy] = 0;
7833 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
7834 if ((fillval == 0 || aux != fillval)
7835 && (missval == 0 || aux != missval)
7836 && fabsf(aux) < 1e14f)
7837 dest[ix][iy] += scl * aux;
7838 else
7839 dest[ix][iy] = NAN;
7840 }
7841
7842 } else {
7843
7844 /* Copy and check data (ordering: lon, lat)... */
7845#pragma omp parallel for default(shared) num_threads(12)
7846 for (int iy = 0; iy < met->ny; iy++)
7847 for (int ix = 0; ix < met->nx; ix++) {
7848 if (init)
7849 dest[ix][iy] = 0;
7850 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
7851 if ((fillval == 0 || aux != fillval)
7852 && (missval == 0 || aux != missval)
7853 && fabsf(aux) < 1e14f)
7854 dest[ix][iy] += scl * aux;
7855 else
7856 dest[ix][iy] = NAN;
7857 }
7858 }
7859
7860 /* Free... */
7861 free(help);
7862 }
7863
7864 /* Return... */
7865 return 1;
7866}
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2500
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2486

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

7879 {
7880
7881 char varsel[LEN];
7882
7883 float offset, scalfac;
7884
7885 int varid;
7886
7887 /* Check if variable exists... */
7888 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7889 sprintf(varsel, "%s", varname);
7890 else if (varname2 != NULL
7891 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7892 sprintf(varsel, "%s", varname2);
7893 else if (varname3 != NULL
7894 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7895 sprintf(varsel, "%s", varname3);
7896 else if (varname4 != NULL
7897 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7898 sprintf(varsel, "%s", varname4);
7899 else
7900 return 0;
7901
7902 /* Read packed data... */
7903 if (ctl->met_nc_scale
7904 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7905 && nc_get_att_float(ncid, varid, "scale_factor",
7906 &scalfac) == NC_NOERR) {
7907
7908 /* Allocate... */
7909 short *help;
7910 ALLOC(help, short,
7911 EX * EY * EP);
7912
7913 /* Read fill value and missing value... */
7914 short fillval, missval;
7915 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7916 fillval = 0;
7917 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7918 missval = 0;
7919
7920 /* Write info... */
7921 LOG(2, "Read 3-D variable: %s "
7922 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7923 varsel, fillval, missval, scalfac, offset);
7924
7925 /* Read data... */
7926 NC(nc_get_var_short(ncid, varid, help));
7927
7928 /* Check meteo data layout... */
7929 if (ctl->met_convention != 0)
7930 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7931
7932 /* Copy and check data... */
7933#pragma omp parallel for default(shared) num_threads(12)
7934 for (int ix = 0; ix < met->nx; ix++)
7935 for (int iy = 0; iy < met->ny; iy++)
7936 for (int ip = 0; ip < met->np; ip++) {
7937 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7938 if ((fillval == 0 || aux != fillval)
7939 && (missval == 0 || aux != missval)
7940 && fabsf(aux * scalfac + offset) < 1e14f)
7941 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
7942 else
7943 dest[ix][iy][ip] = NAN;
7944 }
7945
7946 /* Free... */
7947 free(help);
7948 }
7949
7950 /* Unpacked data... */
7951 else {
7952
7953 /* Allocate... */
7954 float *help;
7955 ALLOC(help, float,
7956 EX * EY * EP);
7957
7958 /* Read fill value and missing value... */
7959 float fillval, missval;
7960 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7961 fillval = 0;
7962 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7963 missval = 0;
7964
7965 /* Write info... */
7966 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
7967 varsel, fillval, missval);
7968
7969 /* Read data... */
7970 NC(nc_get_var_float(ncid, varid, help));
7971
7972 /* Check meteo data layout... */
7973 if (ctl->met_convention == 0) {
7974
7975 /* Copy and check data (ordering: lev, lat, lon)... */
7976#pragma omp parallel for default(shared) num_threads(12)
7977 for (int ix = 0; ix < met->nx; ix++)
7978 for (int iy = 0; iy < met->ny; iy++)
7979 for (int ip = 0; ip < met->np; ip++) {
7980 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7981 if ((fillval == 0 || aux != fillval)
7982 && (missval == 0 || aux != missval)
7983 && fabsf(aux) < 1e14f)
7984 dest[ix][iy][ip] = scl * aux;
7985 else
7986 dest[ix][iy][ip] = NAN;
7987 }
7988
7989 } else {
7990
7991 /* Copy and check data (ordering: lon, lat, lev)... */
7992#pragma omp parallel for default(shared) num_threads(12)
7993 for (int ip = 0; ip < met->np; ip++)
7994 for (int iy = 0; iy < met->ny; iy++)
7995 for (int ix = 0; ix < met->nx; ix++) {
7996 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7997 if ((fillval == 0 || aux != fillval)
7998 && (missval == 0 || aux != missval)
7999 && fabsf(aux) < 1e14f)
8000 dest[ix][iy][ip] = scl * aux;
8001 else
8002 dest[ix][iy][ip] = NAN;
8003 }
8004 }
8005
8006 /* Free... */
8007 free(help);
8008 }
8009
8010 /* Return... */
8011 return 1;
8012}

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

8018 {
8019
8020 /* Set timer... */
8021 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
8022 LOG(2, "Calculate planetary boundary layer...");
8023
8024 /* Convert PBL height from meteo file to pressure... */
8025 if (ctl->met_pbl == 1) {
8026
8027 /* Loop over grid points... */
8028#pragma omp parallel for default(shared) collapse(2)
8029 for (int ix = 0; ix < met->nx; ix++)
8030 for (int iy = 0; iy < met->ny; iy++) {
8031
8032 /* Get pressure at top of PBL... */
8033 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
8034 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
8035 met->pbl[ix][iy] =
8036 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
8037 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
8038 }
8039 }
8040
8041 /* Determine PBL based on Richardson number... */
8042 else if (ctl->met_pbl == 2) {
8043
8044 /* Parameters used to estimate the height of the PBL
8045 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
8046 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
8047
8048 /* Loop over grid points... */
8049#pragma omp parallel for default(shared) collapse(2)
8050 for (int ix = 0; ix < met->nx; ix++)
8051 for (int iy = 0; iy < met->ny; iy++) {
8052
8053 /* Set bottom level of PBL... */
8054 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
8055
8056 /* Find lowest level near the bottom... */
8057 int ip;
8058 for (ip = 1; ip < met->np; ip++)
8059 if (met->p[ip] < pbl_bot)
8060 break;
8061
8062 /* Get near surface data... */
8063 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
8064 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
8065 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
8066
8067 /* Init... */
8068 double rib_old = 0;
8069
8070 /* Loop over levels... */
8071 for (; ip < met->np; ip++) {
8072
8073 /* Get squared horizontal wind speed... */
8074 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
8075 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
8076 vh2 = MAX(vh2, SQR(umin));
8077
8078 /* Calculate bulk Richardson number... */
8079 const double rib =
8080 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
8081 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
8082 met->h2o[ix][iy][ip]) - tvs) / vh2;
8083
8084 /* Check for critical value... */
8085 if (rib >= rib_crit) {
8086 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
8087 rib, met->p[ip], rib_crit));
8088 if (met->pbl[ix][iy] > pbl_bot)
8089 met->pbl[ix][iy] = (float) pbl_bot;
8090 break;
8091 }
8092
8093 /* Save Richardson number... */
8094 rib_old = rib;
8095 }
8096 }
8097 }
8098
8099 /* Determine PBL based on potential temperature... */
8100 if (ctl->met_pbl == 3) {
8101
8102 /* Parameters used to estimate the height of the PBL
8103 (following HYSPLIT model)... */
8104 const double dtheta = 2.0, zmin = 0.1;
8105
8106 /* Loop over grid points... */
8107#pragma omp parallel for default(shared) collapse(2)
8108 for (int ix = 0; ix < met->nx; ix++)
8109 for (int iy = 0; iy < met->ny; iy++) {
8110
8111 /* Potential temperature at the surface... */
8112 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
8113
8114 /* Find topmost level where theta exceeds surface value by 2 K... */
8115 int ip;
8116 for (ip = met->np - 2; ip > 0; ip--)
8117 if (met->p[ip] >= 300.)
8118 if (met->p[ip] > met->ps[ix][iy]
8119 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
8120 break;
8121
8122 /* Interpolate... */
8123 met->pbl[ix][iy]
8124 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
8125 met->p[ip + 1],
8126 THETA(met->p[ip], met->t[ix][iy][ip]),
8127 met->p[ip], theta0 + dtheta));
8128
8129 /* Check minimum value... */
8130 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
8131 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
8132 met->pbl[ix][iy] = (float) pbl_min;
8133 }
8134 }
8135
8136 /* Loop over grid points... */
8137#pragma omp parallel for default(shared) collapse(2)
8138 for (int ix = 0; ix < met->nx; ix++)
8139 for (int iy = 0; iy < met->ny; iy++) {
8140
8141 /* Check minimum value... */
8142 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
8143 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
8144
8145 /* Check maximum value... */
8146 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
8147 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
8148 }
8149}
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 8153 of file mptrac.c.

8154 {
8155
8156 /* Set timer... */
8157 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
8158 LOG(2, "Apply periodic boundary conditions...");
8159
8160 /* Check longitudes... */
8161 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
8162 + met->lon[1] - met->lon[0] - 360) < 0.01))
8163 return;
8164
8165 /* Increase longitude counter... */
8166 if ((++met->nx) >= EX)
8167 ERRMSG("Cannot create periodic boundary conditions!");
8168
8169 /* Set longitude... */
8170 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
8171
8172 /* Loop over latitudes and pressure levels... */
8173#pragma omp parallel for default(shared)
8174 for (int iy = 0; iy < met->ny; iy++) {
8175 met->ps[met->nx - 1][iy] = met->ps[0][iy];
8176 met->zs[met->nx - 1][iy] = met->zs[0][iy];
8177 met->ts[met->nx - 1][iy] = met->ts[0][iy];
8178 met->us[met->nx - 1][iy] = met->us[0][iy];
8179 met->vs[met->nx - 1][iy] = met->vs[0][iy];
8180 met->ess[met->nx - 1][iy] = met->ess[0][iy];
8181 met->nss[met->nx - 1][iy] = met->nss[0][iy];
8182 met->shf[met->nx - 1][iy] = met->shf[0][iy];
8183 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
8184 met->sst[met->nx - 1][iy] = met->sst[0][iy];
8185 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
8186 met->cape[met->nx - 1][iy] = met->cape[0][iy];
8187 met->cin[met->nx - 1][iy] = met->cin[0][iy];
8188 for (int ip = 0; ip < met->np; ip++) {
8189 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
8190 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
8191 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
8192 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
8193 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
8194 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
8195 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
8196 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
8197 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
8198 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
8199 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
8200 }
8201 for (int ip = 0; ip < met->npl; ip++) {
8202 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
8203 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
8204 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
8205 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
8206 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
8207 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
8208 }
8209 }
8210}

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

8215 {
8216
8217 /* Set timer... */
8218 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
8219 LOG(2, "Apply fix for polar winds...");
8220
8221 /* Check latitudes... */
8222 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
8223 return;
8224
8225 /* Loop over hemispheres... */
8226 for (int ihem = 0; ihem < 2; ihem++) {
8227
8228 /* Set latitude indices... */
8229 int i89 = 1, i90 = 0, sign = 1;
8230 if (ihem == 1) {
8231 i89 = met->ny - 2;
8232 i90 = met->ny - 1;
8233 }
8234 if (met->lat[i90] < 0)
8235 sign = -1;
8236
8237 /* Look-up table of cosinus and sinus... */
8238 double clon[EX], slon[EX];
8239#pragma omp parallel for default(shared)
8240 for (int ix = 0; ix < met->nx; ix++) {
8241 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
8242 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
8243 }
8244
8245 /* Loop over levels... */
8246#pragma omp parallel for default(shared)
8247 for (int ip = 0; ip < met->np; ip++) {
8248
8249 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
8250 double vel89x = 0, vel89y = 0;
8251 for (int ix = 0; ix < met->nx; ix++) {
8252 vel89x +=
8253 (met->u[ix][i89][ip] * clon[ix] -
8254 met->v[ix][i89][ip] * slon[ix]) / met->nx;
8255 vel89y +=
8256 (met->u[ix][i89][ip] * slon[ix] +
8257 met->v[ix][i89][ip] * clon[ix]) / met->nx;
8258 }
8259
8260 /* Replace 90 degree winds by 89 degree mean... */
8261 for (int ix = 0; ix < met->nx; ix++) {
8262 met->u[ix][i90][ip]
8263 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
8264 met->v[ix][i90][ip]
8265 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
8266 }
8267 }
8268 }
8269}

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

8274 {
8275
8276 double pows[EP];
8277
8278 /* Set timer... */
8279 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
8280 LOG(2, "Calculate potential vorticity...");
8281
8282 /* Set powers... */
8283#pragma omp parallel for default(shared)
8284 for (int ip = 0; ip < met->np; ip++)
8285 pows[ip] = pow(1000. / met->p[ip], 0.286);
8286
8287 /* Loop over grid points... */
8288#pragma omp parallel for default(shared)
8289 for (int ix = 0; ix < met->nx; ix++) {
8290
8291 /* Set indices... */
8292 const int ix0 = MAX(ix - 1, 0);
8293 const int ix1 = MIN(ix + 1, met->nx - 1);
8294
8295 /* Loop over grid points... */
8296 for (int iy = 0; iy < met->ny; iy++) {
8297
8298 /* Set indices... */
8299 const int iy0 = MAX(iy - 1, 0);
8300 const int iy1 = MIN(iy + 1, met->ny - 1);
8301
8302 /* Set auxiliary variables... */
8303 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
8304 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
8305 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
8306 const double c0 = cos(DEG2RAD(met->lat[iy0]));
8307 const double c1 = cos(DEG2RAD(met->lat[iy1]));
8308 const double cr = cos(DEG2RAD(latr));
8309 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
8310
8311 /* Loop over grid points... */
8312 for (int ip = 0; ip < met->np; ip++) {
8313
8314 /* Get gradients in longitude... */
8315 const double dtdx
8316 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
8317 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
8318
8319 /* Get gradients in latitude... */
8320 const double dtdy
8321 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
8322 const double dudy
8323 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
8324
8325 /* Set indices... */
8326 const int ip0 = MAX(ip - 1, 0);
8327 const int ip1 = MIN(ip + 1, met->np - 1);
8328
8329 /* Get gradients in pressure... */
8330 double dtdp, dudp, dvdp;
8331 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
8332 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
8333 if (ip != ip0 && ip != ip1) {
8334 double denom = dp0 * dp1 * (dp0 + dp1);
8335 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
8336 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
8337 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
8338 / denom;
8339 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
8340 - dp1 * dp1 * met->u[ix][iy][ip0]
8341 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
8342 / denom;
8343 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
8344 - dp1 * dp1 * met->v[ix][iy][ip0]
8345 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
8346 / denom;
8347 } else {
8348 const double denom = dp0 + dp1;
8349 dtdp =
8350 (met->t[ix][iy][ip1] * pows[ip1] -
8351 met->t[ix][iy][ip0] * pows[ip0]) / denom;
8352 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
8353 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
8354 }
8355
8356 /* Calculate PV... */
8357 met->pv[ix][iy][ip] = (float)
8358 (1e6 * G0 *
8359 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
8360 }
8361 }
8362 }
8363
8364 /* Fix for polar regions... */
8365#pragma omp parallel for default(shared)
8366 for (int ix = 0; ix < met->nx; ix++)
8367 for (int ip = 0; ip < met->np; ip++) {
8368 met->pv[ix][0][ip]
8369 = met->pv[ix][1][ip]
8370 = met->pv[ix][2][ip];
8371 met->pv[ix][met->ny - 1][ip]
8372 = met->pv[ix][met->ny - 2][ip]
8373 = met->pv[ix][met->ny - 3][ip];
8374 }
8375}
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:472
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:451

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

8380 {
8381
8382 /* Set timer... */
8383 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
8384 LOG(2, "Calculate total column ozone...");
8385
8386 /* Loop over columns... */
8387#pragma omp parallel for default(shared) collapse(2)
8388 for (int ix = 0; ix < met->nx; ix++)
8389 for (int iy = 0; iy < met->ny; iy++) {
8390
8391 /* Integrate... */
8392 double cd = 0;
8393 for (int ip = 1; ip < met->np; ip++)
8394 if (met->p[ip - 1] <= met->ps[ix][iy]) {
8395 const double vmr =
8396 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
8397 const double dp = met->p[ip - 1] - met->p[ip];
8398 cd += vmr * MO3 / MA * dp * 1e2 / G0;
8399 }
8400
8401 /* Convert to Dobson units... */
8402 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
8403 }
8404}

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

8410 {
8411
8412 met_t *help;
8413
8414 /* Check parameters... */
8415 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
8416 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
8417 return;
8418
8419 /* Set timer... */
8420 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
8421 LOG(2, "Downsampling of meteo data...");
8422
8423 /* Allocate... */
8424 ALLOC(help, met_t, 1);
8425
8426 /* Copy data... */
8427 help->nx = met->nx;
8428 help->ny = met->ny;
8429 help->np = met->np;
8430 memcpy(help->lon, met->lon, sizeof(met->lon));
8431 memcpy(help->lat, met->lat, sizeof(met->lat));
8432 memcpy(help->p, met->p, sizeof(met->p));
8433
8434 /* Smoothing... */
8435 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
8436 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
8437 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
8438 help->ps[ix][iy] = 0;
8439 help->zs[ix][iy] = 0;
8440 help->ts[ix][iy] = 0;
8441 help->us[ix][iy] = 0;
8442 help->vs[ix][iy] = 0;
8443 help->ess[ix][iy] = 0;
8444 help->nss[ix][iy] = 0;
8445 help->shf[ix][iy] = 0;
8446 help->lsm[ix][iy] = 0;
8447 help->sst[ix][iy] = 0;
8448 help->pbl[ix][iy] = 0;
8449 help->cape[ix][iy] = 0;
8450 help->cin[ix][iy] = 0;
8451 help->t[ix][iy][ip] = 0;
8452 help->u[ix][iy][ip] = 0;
8453 help->v[ix][iy][ip] = 0;
8454 help->w[ix][iy][ip] = 0;
8455 help->h2o[ix][iy][ip] = 0;
8456 help->o3[ix][iy][ip] = 0;
8457 help->lwc[ix][iy][ip] = 0;
8458 help->rwc[ix][iy][ip] = 0;
8459 help->iwc[ix][iy][ip] = 0;
8460 help->swc[ix][iy][ip] = 0;
8461 help->cc[ix][iy][ip] = 0;
8462 float wsum = 0;
8463 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
8464 ix2++) {
8465 int ix3 = ix2;
8466 if (ix3 < 0)
8467 ix3 += met->nx;
8468 else if (ix3 >= met->nx)
8469 ix3 -= met->nx;
8470
8471 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
8472 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
8473 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
8474 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
8475 float w = (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
8476 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
8477 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
8478 help->ps[ix][iy] += w * met->ps[ix3][iy2];
8479 help->zs[ix][iy] += w * met->zs[ix3][iy2];
8480 help->ts[ix][iy] += w * met->ts[ix3][iy2];
8481 help->us[ix][iy] += w * met->us[ix3][iy2];
8482 help->vs[ix][iy] += w * met->vs[ix3][iy2];
8483 help->ess[ix][iy] += w * met->ess[ix3][iy2];
8484 help->nss[ix][iy] += w * met->nss[ix3][iy2];
8485 help->shf[ix][iy] += w * met->shf[ix3][iy2];
8486 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
8487 help->sst[ix][iy] += w * met->sst[ix3][iy2];
8488 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
8489 help->cape[ix][iy] += w * met->cape[ix3][iy2];
8490 help->cin[ix][iy] += w * met->cin[ix3][iy2];
8491 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
8492 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
8493 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
8494 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
8495 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
8496 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
8497 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
8498 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
8499 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
8500 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
8501 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
8502 wsum += w;
8503 }
8504 }
8505 help->ps[ix][iy] /= wsum;
8506 help->zs[ix][iy] /= wsum;
8507 help->ts[ix][iy] /= wsum;
8508 help->us[ix][iy] /= wsum;
8509 help->vs[ix][iy] /= wsum;
8510 help->ess[ix][iy] /= wsum;
8511 help->nss[ix][iy] /= wsum;
8512 help->shf[ix][iy] /= wsum;
8513 help->lsm[ix][iy] /= wsum;
8514 help->sst[ix][iy] /= wsum;
8515 help->pbl[ix][iy] /= wsum;
8516 help->cape[ix][iy] /= wsum;
8517 help->cin[ix][iy] /= wsum;
8518 help->t[ix][iy][ip] /= wsum;
8519 help->u[ix][iy][ip] /= wsum;
8520 help->v[ix][iy][ip] /= wsum;
8521 help->w[ix][iy][ip] /= wsum;
8522 help->h2o[ix][iy][ip] /= wsum;
8523 help->o3[ix][iy][ip] /= wsum;
8524 help->lwc[ix][iy][ip] /= wsum;
8525 help->rwc[ix][iy][ip] /= wsum;
8526 help->iwc[ix][iy][ip] /= wsum;
8527 help->swc[ix][iy][ip] /= wsum;
8528 help->cc[ix][iy][ip] /= wsum;
8529 }
8530 }
8531 }
8532
8533 /* Downsampling... */
8534 met->nx = 0;
8535 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
8536 met->lon[met->nx] = help->lon[ix];
8537 met->ny = 0;
8538 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
8539 met->lat[met->ny] = help->lat[iy];
8540 met->ps[met->nx][met->ny] = help->ps[ix][iy];
8541 met->zs[met->nx][met->ny] = help->zs[ix][iy];
8542 met->ts[met->nx][met->ny] = help->ts[ix][iy];
8543 met->us[met->nx][met->ny] = help->us[ix][iy];
8544 met->vs[met->nx][met->ny] = help->vs[ix][iy];
8545 met->ess[met->nx][met->ny] = help->ess[ix][iy];
8546 met->nss[met->nx][met->ny] = help->nss[ix][iy];
8547 met->shf[met->nx][met->ny] = help->shf[ix][iy];
8548 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
8549 met->sst[met->nx][met->ny] = help->sst[ix][iy];
8550 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
8551 met->cape[met->nx][met->ny] = help->cape[ix][iy];
8552 met->cin[met->nx][met->ny] = help->cin[ix][iy];
8553 met->np = 0;
8554 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
8555 met->p[met->np] = help->p[ip];
8556 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
8557 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
8558 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
8559 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
8560 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
8561 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
8562 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
8563 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
8564 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
8565 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
8566 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
8567 met->np++;
8568 }
8569 met->ny++;
8570 }
8571 met->nx++;
8572 }
8573
8574 /* Free... */
8575 free(help);
8576}
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2576
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2582
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2579
int met_dx
Stride for longitudes.
Definition: mptrac.h:2570
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2585
int met_dy
Stride for latitudes.
Definition: mptrac.h:2573

◆ read_met_surface()

void read_met_surface ( const int  ncid,
const ctl_t ctl,
met_t met 
)

Reads surface meteorological data from a netCDF file and stores it in the meteorological data structure.

This function reads various surface meteorological variables from a netCDF file and stores them in the provided meteorological data structure. Depending on the configuration, it may read data for surface pressure, geopotential height, temperature, zonal and meridional wind components, land-sea mask, and sea surface temperature.

Parameters
ncidNetCDF file identifier.
metA pointer to the meteorological data structure to store the read data.
ctlA pointer to a structure containing control parameters.

The function performs the following steps:

  • Sets a timer for performance monitoring.
  • Reads surface meteorological data based on the configuration:
    • For MPTRAC meteorological data:
      • Reads surface pressure from "lnsp", "ps", or "sp" variables.
      • Converts surface pressure to Pa if necessary.
      • Reads geopotential height at the surface from "z" or "zm" variables.
      • Reads surface temperature from "t2m" or "2t" variables.
      • Reads zonal wind at the surface from "u10m" or "10u" variables.
      • Reads meridional wind at the surface from "v10m" or "10v" variables.
      • Reads land-sea mask from "lsm" variable.
      • Reads sea surface temperature from "sstk" or "sst" variables.
    • For CLaMS meteorological data:
      • Reads surface pressure from "ps" variable.
      • Reads geopotential height at the surface using the lowest level of the 3-D data field.
      • Reads surface temperature from "t2" variable.
      • Reads zonal wind at the surface from "u10" variable.
      • Reads meridional wind at the surface from "v10" variable.
      • Reads land-sea mask from "lsm" variable.
      • Reads sea surface temperature from "sstk" variable.
Note
The function handles different variable names and units according to the specified meteorological data source (MPTRAC or CLaMS).
Authors
Lars Hoffmann
Jan Clemens

Definition at line 8580 of file mptrac.c.

8583 {
8584
8585 /* Set timer... */
8586 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
8587 LOG(2, "Read surface data...");
8588
8589 /* Read surface pressure... */
8590 if (read_met_nc_2d
8591 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, met->ps, 1.0f,
8592 1)) {
8593 for (int ix = 0; ix < met->nx; ix++)
8594 for (int iy = 0; iy < met->ny; iy++)
8595 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8596 } else
8597 if (!read_met_nc_2d
8598 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, met->ps, 0.01f,
8599 1)) {
8600 WARN("Cannot not read surface pressure data (use lowest level)!");
8601 for (int ix = 0; ix < met->nx; ix++)
8602 for (int iy = 0; iy < met->ny; iy++)
8603 met->ps[ix][iy]
8604 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8605 }
8606
8607 /* MPTRAC meteo data... */
8608 if (ctl->met_clams == 0) {
8609
8610 /* Read geopotential height at the surface... */
8611 if (!read_met_nc_2d
8612 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, met->zs,
8613 (float) (1. / (1000. * G0)), 1))
8614 if (!read_met_nc_2d
8615 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, met->zs,
8616 (float) (1. / 1000.), 1))
8617 WARN("Cannot read surface geopotential height!");
8618 }
8619
8620 /* CLaMS meteo data... */
8621 else {
8622
8623 /* Read geopotential height at the surface
8624 (use lowermost level of 3-D data field)... */
8625 float *help;
8626 ALLOC(help, float,
8627 EX * EY * EP);
8628 memcpy(help, met->pl, sizeof(met->pl));
8629 if (!read_met_nc_3d
8630 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
8631 (float) (1e-3 / G0)))
8632 ERRMSG("Cannot read geopotential height!");
8633 for (int ix = 0; ix < met->nx; ix++)
8634 for (int iy = 0; iy < met->ny; iy++)
8635 met->zs[ix][iy] = met->pl[ix][iy][0];
8636 memcpy(met->pl, help, sizeof(met->pl));
8637 free(help);
8638 }
8639
8640 /* Read temperature at the surface... */
8641 if (!read_met_nc_2d
8642 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, met->ts, 1.0, 1))
8643 WARN("Cannot read surface temperature!");
8644
8645 /* Read zonal wind at the surface... */
8646 if (!read_met_nc_2d
8647 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, met->us,
8648 1.0, 1))
8649 WARN("Cannot read surface zonal wind!");
8650
8651 /* Read meridional wind at the surface... */
8652 if (!read_met_nc_2d
8653 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, met->vs,
8654 1.0, 1))
8655 WARN("Cannot read surface meridional wind!");
8656
8657 /* Read eastward turbulent surface stress... */
8658 if (!read_met_nc_2d
8659 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, met->ess, 1.0,
8660 1))
8661 WARN("Cannot read eastward turbulent surface stress!");
8662
8663 /* Read northward turbulent surface stress... */
8664 if (!read_met_nc_2d
8665 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, met->nss, 1.0,
8666 1))
8667 WARN("Cannot read nothward turbulent surface stress!");
8668
8669 /* Read surface sensible heat flux... */
8670 if (!read_met_nc_2d
8671 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, met->shf, 1.0,
8672 1))
8673 WARN("Cannot read surface sensible heat flux!");
8674
8675 /* Read land-sea mask... */
8676 if (!read_met_nc_2d
8677 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, met->lsm, 1.0,
8678 1))
8679 WARN("Cannot read land-sea mask!");
8680
8681 /* Read sea surface temperature... */
8682 if (!read_met_nc_2d
8683 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, met->sst,
8684 1.0, 1))
8685 WARN("Cannot read sea surface temperature!");
8686
8687 /* Read PBL... */
8688 if (ctl->met_pbl == 0)
8689 if (!read_met_nc_2d
8690 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
8691 0.01f, 1))
8692 WARN("Cannot read planetary boundary layer pressure!");
8693 if (ctl->met_pbl == 1)
8694 if (!read_met_nc_2d
8695 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
8696 0.001f, 1))
8697 WARN("Cannot read planetary boundary layer height!");
8698
8699 /* Read CAPE... */
8700 if (ctl->met_cape == 0)
8701 if (!read_met_nc_2d
8702 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, met->cape,
8703 1.0, 1))
8704 WARN("Cannot read CAPE!");
8705
8706 /* Read CIN... */
8707 if (ctl->met_cape == 0)
8708 if (!read_met_nc_2d
8709 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, met->cin,
8710 1.0, 1))
8711 WARN("Cannot read convective inhibition!");
8712}
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, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:7712
Here is the call graph for this function:

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

8719 {
8720
8721 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
8722 th2[200], z[EP], z2[200];
8723
8724 /* Set timer... */
8725 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
8726 LOG(2, "Calculate tropopause...");
8727
8728 /* Get altitude and pressure profiles... */
8729#pragma omp parallel for default(shared)
8730 for (int iz = 0; iz < met->np; iz++)
8731 z[iz] = Z(met->p[iz]);
8732#pragma omp parallel for default(shared)
8733 for (int iz = 0; iz <= 190; iz++) {
8734 z2[iz] = 4.5 + 0.1 * iz;
8735 p2[iz] = P(z2[iz]);
8736 }
8737
8738 /* Do not calculate tropopause... */
8739 if (ctl->met_tropo == 0)
8740#pragma omp parallel for default(shared) collapse(2)
8741 for (int ix = 0; ix < met->nx; ix++)
8742 for (int iy = 0; iy < met->ny; iy++)
8743 met->pt[ix][iy] = NAN;
8744
8745 /* Use tropopause climatology... */
8746 else if (ctl->met_tropo == 1) {
8747#pragma omp parallel for default(shared) collapse(2)
8748 for (int ix = 0; ix < met->nx; ix++)
8749 for (int iy = 0; iy < met->ny; iy++)
8750 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
8751 }
8752
8753 /* Use cold point... */
8754 else if (ctl->met_tropo == 2) {
8755
8756 /* Loop over grid points... */
8757#pragma omp parallel for default(shared) private(t,t2) collapse(2)
8758 for (int ix = 0; ix < met->nx; ix++)
8759 for (int iy = 0; iy < met->ny; iy++) {
8760
8761 /* Interpolate temperature profile... */
8762 for (int iz = 0; iz < met->np; iz++)
8763 t[iz] = met->t[ix][iy][iz];
8764 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
8765
8766 /* Find minimum... */
8767 int iz = (int) gsl_stats_min_index(t2, 1, 171);
8768 if (iz > 0 && iz < 170)
8769 met->pt[ix][iy] = (float) p2[iz];
8770 else
8771 met->pt[ix][iy] = NAN;
8772 }
8773 }
8774
8775 /* Use WMO definition... */
8776 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
8777
8778 /* Loop over grid points... */
8779#pragma omp parallel for default(shared) private(t,t2) collapse(2)
8780 for (int ix = 0; ix < met->nx; ix++)
8781 for (int iy = 0; iy < met->ny; iy++) {
8782
8783 /* Interpolate temperature profile... */
8784 int iz;
8785 for (iz = 0; iz < met->np; iz++)
8786 t[iz] = met->t[ix][iy][iz];
8787 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
8788
8789 /* Find 1st tropopause... */
8790 met->pt[ix][iy] = NAN;
8791 for (iz = 0; iz <= 170; iz++) {
8792 int found = 1;
8793 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
8794 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
8795 found = 0;
8796 break;
8797 }
8798 if (found) {
8799 if (iz > 0 && iz < 170)
8800 met->pt[ix][iy] = (float) p2[iz];
8801 break;
8802 }
8803 }
8804
8805 /* Find 2nd tropopause... */
8806 if (ctl->met_tropo == 4) {
8807 met->pt[ix][iy] = NAN;
8808 for (; iz <= 170; iz++) {
8809 int found = 1;
8810 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
8811 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
8812 found = 0;
8813 break;
8814 }
8815 if (found)
8816 break;
8817 }
8818 for (; iz <= 170; iz++) {
8819 int found = 1;
8820 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
8821 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
8822 found = 0;
8823 break;
8824 }
8825 if (found) {
8826 if (iz > 0 && iz < 170)
8827 met->pt[ix][iy] = (float) p2[iz];
8828 break;
8829 }
8830 }
8831 }
8832 }
8833 }
8834
8835 /* Use dynamical tropopause... */
8836 else if (ctl->met_tropo == 5) {
8837
8838 /* Loop over grid points... */
8839#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
8840 for (int ix = 0; ix < met->nx; ix++)
8841 for (int iy = 0; iy < met->ny; iy++) {
8842
8843 /* Interpolate potential vorticity profile... */
8844 for (int iz = 0; iz < met->np; iz++)
8845 pv[iz] = met->pv[ix][iy][iz];
8846 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
8847
8848 /* Interpolate potential temperature profile... */
8849 for (int iz = 0; iz < met->np; iz++)
8850 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
8851 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
8852
8853 /* Find dynamical tropopause... */
8854 met->pt[ix][iy] = NAN;
8855 for (int iz = 0; iz <= 170; iz++)
8856 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
8857 || th2[iz] >= ctl->met_tropo_theta) {
8858 if (iz > 0 && iz < 170)
8859 met->pt[ix][iy] = (float) p2[iz];
8860 break;
8861 }
8862 }
8863 }
8864
8865 else
8866 ERRMSG("Cannot calculate tropopause!");
8867
8868 /* Interpolate temperature, geopotential height, and water vapor... */
8869#pragma omp parallel for default(shared) collapse(2)
8870 for (int ix = 0; ix < met->nx; ix++)
8871 for (int iy = 0; iy < met->ny; iy++) {
8872 double h2ot, tt, zt;
8874 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
8875 met->lat[iy], &tt, ci, cw, 1);
8876 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
8877 met->lat[iy], &zt, ci, cw, 0);
8878 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
8879 met->lat[iy], &h2ot, ci, cw, 0);
8880 met->tt[ix][iy] = (float) tt;
8881 met->zt[ix][iy] = (float) zt;
8882 met->h2ot[ix][iy] = (float) h2ot;
8883 }
8884}
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:9094
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:851
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 8888 of file mptrac.c.

8896 {
8897
8898 /* Write info... */
8899 LOG(1, "Read observation data: %s", filename);
8900
8901 /* Read data... */
8902 if (ctl->obs_type == 0)
8903 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
8904 else if (ctl->obs_type == 1)
8905 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
8906 else
8907 ERRMSG("Set OBS_TYPE to 0 or 1!");
8908
8909 /* Check time... */
8910 for (int i = 1; i < *nobs; i++)
8911 if (rt[i] < rt[i - 1])
8912 ERRMSG("Time must be ascending!");
8913
8914 /* Write info... */
8915 int n = *nobs;
8916 double mini, maxi;
8917 LOG(2, "Number of observations: %d", *nobs);
8918 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
8919 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8920 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
8921 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
8922 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
8923 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
8924 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
8925 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
8926 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
8927 LOG(2, "Observation range: %g ... %g", mini, maxi);
8928}
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:8932
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:8960
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 8932 of file mptrac.c.

8939 {
8940
8941 /* Open observation data file... */
8942 FILE *in;
8943 if (!(in = fopen(filename, "r")))
8944 ERRMSG("Cannot open file!");
8945
8946 /* Read observations... */
8947 char line[LEN];
8948 while (fgets(line, LEN, in))
8949 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
8950 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
8951 if ((++(*nobs)) >= NOBS)
8952 ERRMSG("Too many observations!");
8953
8954 /* Close observation data file... */
8955 fclose(in);
8956}
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:292

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

8967 {
8968
8969 int ncid, varid;
8970
8971 /* Open netCDF file... */
8972 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8973 ERRMSG("Cannot open file!");
8974
8975 /* Read the observations from the NetCDF file... */
8976 NC_INQ_DIM("nobs", nobs, 1, NOBS);
8977 NC_GET_DOUBLE("time", rt, 1);
8978 NC_GET_DOUBLE("alt", rz, 1);
8979 NC_GET_DOUBLE("lon", rlon, 1);
8980 NC_GET_DOUBLE("lat", rlat, 1);
8981 NC_GET_DOUBLE("obs", robs, 1);
8982
8983 /* Close file... */
8984 NC(nc_close(ncid));
8985}

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

8996 {
8997
8998 FILE *in = NULL;
8999
9000 char fullname1[LEN], fullname2[LEN], rval[LEN];
9001
9002 int contain = 0, i;
9003
9004 /* Open file... */
9005 if (filename[strlen(filename) - 1] != '-')
9006 if (!(in = fopen(filename, "r")))
9007 ERRMSG("Cannot open file!");
9008
9009 /* Set full variable name... */
9010 if (arridx >= 0) {
9011 sprintf(fullname1, "%s[%d]", varname, arridx);
9012 sprintf(fullname2, "%s[*]", varname);
9013 } else {
9014 sprintf(fullname1, "%s", varname);
9015 sprintf(fullname2, "%s", varname);
9016 }
9017
9018 /* Read data... */
9019 if (in != NULL) {
9020 char dummy[LEN], line[LEN], rvarname[LEN];
9021 while (fgets(line, LEN, in)) {
9022 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
9023 if (strcasecmp(rvarname, fullname1) == 0 ||
9024 strcasecmp(rvarname, fullname2) == 0) {
9025 contain = 1;
9026 break;
9027 }
9028 }
9029 }
9030 for (i = 1; i < argc - 1; i++)
9031 if (strcasecmp(argv[i], fullname1) == 0 ||
9032 strcasecmp(argv[i], fullname2) == 0) {
9033 sprintf(rval, "%s", argv[i + 1]);
9034 contain = 1;
9035 break;
9036 }
9037
9038 /* Close file... */
9039 if (in != NULL)
9040 fclose(in);
9041
9042 /* Check for missing variables... */
9043 if (!contain) {
9044 if (strlen(defvalue) > 0)
9045 sprintf(rval, "%s", defvalue);
9046 else
9047 ERRMSG("Missing variable %s!\n", fullname1);
9048 }
9049
9050 /* Write info... */
9051 LOG(1, "%s = %s", fullname1, rval);
9052
9053 /* Return values... */
9054 if (value != NULL)
9055 sprintf(value, "%s", rval);
9056 return atof(rval);
9057}

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

9065 {
9066
9067 /* Convert particle radius from microns to m... */
9068 const double rp_help = rp * 1e-6;
9069
9070 /* Density of dry air [kg / m^3]... */
9071 const double rho = RHO(p, T);
9072
9073 /* Dynamic viscosity of air [kg / (m s)]... */
9074 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
9075
9076 /* Thermal velocity of an air molecule [m / s]... */
9077 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
9078
9079 /* Mean free path of an air molecule [m]... */
9080 const double lambda = 2. * eta / (rho * v);
9081
9082 /* Knudsen number for air (dimensionless)... */
9083 const double K = lambda / rp_help;
9084
9085 /* Cunningham slip-flow correction (dimensionless)... */
9086 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
9087
9088 /* Sedimentation velocity [m / s]... */
9089 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
9090}
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:203

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

9101 {
9102
9103 /* Cubic spline interpolation... */
9104 if (method == 1) {
9105
9106 /* Allocate... */
9107 gsl_interp_accel *acc = gsl_interp_accel_alloc();
9108 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
9109
9110 /* Interpolate profile... */
9111 gsl_spline_init(s, x, y, (size_t) n);
9112 for (int i = 0; i < n2; i++)
9113 if (x2[i] <= x[0])
9114 y2[i] = y[0];
9115 else if (x2[i] >= x[n - 1])
9116 y2[i] = y[n - 1];
9117 else
9118 y2[i] = gsl_spline_eval(s, x2[i], acc);
9119
9120 /* Free... */
9121 gsl_spline_free(s);
9122 gsl_interp_accel_free(acc);
9123 }
9124
9125 /* Linear interpolation... */
9126 else {
9127 for (int i = 0; i < n2; i++)
9128 if (x2[i] <= x[0])
9129 y2[i] = y[0];
9130 else if (x2[i] >= x[n - 1])
9131 y2[i] = y[n - 1];
9132 else {
9133 int idx = locate_irr(x, n, x2[i]);
9134 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
9135 }
9136 }
9137}
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 9141 of file mptrac.c.

9143 {
9144
9145 if (n <= 0)
9146 return 0;
9147
9148 float mean = 0, var = 0;
9149
9150 for (int i = 0; i < n; ++i) {
9151 mean += data[i];
9152 var += SQR(data[i]);
9153 }
9154
9155 var = var / (float) n - SQR(mean / (float) n);
9156
9157 return (var > 0 ? sqrtf(var) : 0);
9158}

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

9165 {
9166
9167 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
9168 const double D = sec / 86400 - 0.5;
9169
9170 /* Geocentric apparent ecliptic longitude [rad]... */
9171 const double g = DEG2RAD(357.529 + 0.98560028 * D);
9172 const double q = 280.459 + 0.98564736 * D;
9173 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
9174
9175 /* Mean obliquity of the ecliptic [rad]... */
9176 const double e = DEG2RAD(23.439 - 0.00000036 * D);
9177
9178 /* Declination [rad]... */
9179 const double sindec = sin(e) * sin(L);
9180
9181 /* Right ascension [rad]... */
9182 const double ra = atan2(cos(e) * sin(L), cos(L));
9183
9184 /* Greenwich Mean Sidereal Time [h]... */
9185 const double GMST = 18.697374558 + 24.06570982441908 * D;
9186
9187 /* Local Sidereal Time [h]... */
9188 const double LST = GMST + lon / 15;
9189
9190 /* Hour angle [rad]... */
9191 const double h = LST / 12 * M_PI - ra;
9192
9193 /* Convert latitude... */
9194 const double lat_help = DEG2RAD(lat);
9195
9196 /* Return solar zenith angle [rad]... */
9197 return acos(sin(lat_help) * sindec +
9198 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
9199}

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

9211 {
9212
9213 struct tm t0, t1;
9214
9215 t0.tm_year = 100;
9216 t0.tm_mon = 0;
9217 t0.tm_mday = 1;
9218 t0.tm_hour = 0;
9219 t0.tm_min = 0;
9220 t0.tm_sec = 0;
9221
9222 t1.tm_year = year - 1900;
9223 t1.tm_mon = mon - 1;
9224 t1.tm_mday = day;
9225 t1.tm_hour = hour;
9226 t1.tm_min = min;
9227 t1.tm_sec = sec;
9228
9229 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
9230}

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

9237 {
9238
9239 static char names[NTIMER][100], groups[NTIMER][100];
9240
9241 static double rt_name[NTIMER], rt_group[NTIMER],
9242 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
9243
9244 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
9245
9246 /* Get time... */
9247 t1 = omp_get_wtime();
9248 dt = t1 - t0;
9249
9250 /* Add elapsed time to current timers... */
9251 if (iname >= 0) {
9252 rt_name[iname] += dt;
9253 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
9254 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
9255 ct_name[iname]++;
9256 }
9257 if (igroup >= 0)
9258 rt_group[igroup] += t1 - t0;
9259
9260 /* Report timers... */
9261 if (output) {
9262 for (int i = 0; i < nname; i++)
9263 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
9264 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
9265 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
9266 for (int i = 0; i < ngroup; i++)
9267 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
9268 double total = 0.0;
9269 for (int i = 0; i < nname; i++)
9270 total += rt_name[i];
9271 LOG(1, "TIMER_TOTAL = %.3f s", total);
9272 }
9273
9274 /* Identify IDs of next timer... */
9275 for (iname = 0; iname < nname; iname++)
9276 if (strcasecmp(name, names[iname]) == 0)
9277 break;
9278 for (igroup = 0; igroup < ngroup; igroup++)
9279 if (strcasecmp(group, groups[igroup]) == 0)
9280 break;
9281
9282 /* Check whether this is a new timer... */
9283 if (iname >= nname) {
9284 sprintf(names[iname], "%s", name);
9285 if ((++nname) >= NTIMER)
9286 ERRMSG("Too many timers!");
9287 }
9288
9289 /* Check whether this is a new group... */
9290 if (igroup >= ngroup) {
9291 sprintf(groups[igroup], "%s", group);
9292 if ((++ngroup) >= NTIMER)
9293 ERRMSG("Too many groups!");
9294 }
9295
9296 /* Save starting time... */
9297 t0 = t1;
9298}
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:1959

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

9304 {
9305
9306 char tstr[10];
9307
9308 double t;
9309
9310 /* Get time from filename... */
9311 int len = (int) strlen(filename);
9312 sprintf(tstr, "%.4s", &filename[len - offset]);
9313 int year = atoi(tstr);
9314 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
9315 int mon = atoi(tstr);
9316 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
9317 int day = atoi(tstr);
9318 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
9319 int hour = atoi(tstr);
9320 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
9321 int min = atoi(tstr);
9322
9323 /* Check time... */
9324 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
9325 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
9326 ERRMSG("Cannot read time from filename!");
9327
9328 /* Convert time to Julian seconds... */
9329 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
9330
9331 /* Return time... */
9332 return t;
9333}
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 9337 of file mptrac.c.

9340 {
9341
9342 /* Get tropopause pressure... */
9343 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
9344
9345 /* Get pressure range... */
9346 const double p1 = pt * 0.866877899;
9347 const double p0 = pt / 0.866877899;
9348
9349 /* Get weighting factor... */
9350 if (atm->p[ip] > p0)
9351 return 1;
9352 else if (atm->p[ip] < p1)
9353 return 0;
9354 else
9355 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
9356}
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 9360 of file mptrac.c.

9364 {
9365
9366 FILE *out;
9367
9368 /* Set time interval for output... */
9369 const double t0 = t - 0.5 * ctl->dt_mod;
9370 const double t1 = t + 0.5 * ctl->dt_mod;
9371
9372 /* Check if gnuplot output is requested... */
9373 if (ctl->atm_gpfile[0] != '-') {
9374
9375 /* Create gnuplot pipe... */
9376 if (!(out = popen("gnuplot", "w")))
9377 ERRMSG("Cannot create pipe to gnuplot!");
9378
9379 /* Set plot filename... */
9380 fprintf(out, "set out \"%s.png\"\n", filename);
9381
9382 /* Set time string... */
9383 double r;
9384 int year, mon, day, hour, min, sec;
9385 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9386 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
9387 year, mon, day, hour, min);
9388
9389 /* Dump gnuplot file to pipe... */
9390 FILE *in;
9391 if (!(in = fopen(ctl->atm_gpfile, "r")))
9392 ERRMSG("Cannot open file!");
9393 char line[LEN];
9394 while (fgets(line, LEN, in))
9395 fprintf(out, "%s", line);
9396 fclose(in);
9397 }
9398
9399 else {
9400
9401 /* Create file... */
9402 if (!(out = fopen(filename, "w")))
9403 ERRMSG("Cannot create file!");
9404 }
9405
9406 /* Write header... */
9407 fprintf(out,
9408 "# $1 = time [s]\n"
9409 "# $2 = altitude [km]\n"
9410 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
9411 for (int iq = 0; iq < ctl->nq; iq++)
9412 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
9413 ctl->qnt_unit[iq]);
9414 fprintf(out, "\n");
9415
9416 /* Write data... */
9417 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
9418
9419 /* Check time... */
9420 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
9421 continue;
9422
9423 /* Write output... */
9424 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
9425 atm->lon[ip], atm->lat[ip]);
9426 for (int iq = 0; iq < ctl->nq; iq++) {
9427 fprintf(out, " ");
9428 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
9429 fprintf(out, ctl->qnt_format[iq], NAN);
9430 else
9431 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
9432 }
9433 fprintf(out, "\n");
9434 }
9435
9436 /* Close file... */
9437 fclose(out);
9438}
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 9442 of file mptrac.c.

9445 {
9446
9447 FILE *out;
9448
9449 /* Create file... */
9450 if (!(out = fopen(filename, "w")))
9451 ERRMSG("Cannot create file!");
9452
9453 /* Write version of binary data... */
9454 int version = 100;
9455 FWRITE(&version, int,
9456 1,
9457 out);
9458
9459 /* Write data... */
9460 FWRITE(&atm->np, int,
9461 1,
9462 out);
9463 FWRITE(atm->time, double,
9464 (size_t) atm->np,
9465 out);
9466 FWRITE(atm->p, double,
9467 (size_t) atm->np,
9468 out);
9469 FWRITE(atm->lon, double,
9470 (size_t) atm->np,
9471 out);
9472 FWRITE(atm->lat, double,
9473 (size_t) atm->np,
9474 out);
9475 for (int iq = 0; iq < ctl->nq; iq++)
9476 FWRITE(atm->q[iq], double,
9477 (size_t) atm->np,
9478 out);
9479
9480 /* Write final flag... */
9481 int final = 999;
9482 FWRITE(&final, int,
9483 1,
9484 out);
9485
9486 /* Close file... */
9487 fclose(out);
9488}

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

9495 {
9496
9497 int tid, pid, ncid, varid;
9498 size_t start[2], count[2];
9499
9500 /* Create file... */
9501 nc_create(filename, NC_NETCDF4, &ncid);
9502
9503 /* Define dimensions... */
9504 NC(nc_def_dim(ncid, "time", 1, &tid));
9505 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9506
9507 /* Define variables and their attributes... */
9508 int dim_ids[2] = { tid, pid };
9509 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9510 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9511 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
9512 ctl->atm_nc_level, 0);
9513 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
9514 ctl->atm_nc_level, 0);
9515 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
9516 ctl->atm_nc_level, 0);
9517 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
9518 for (int iq = 0; iq < ctl->nq; iq++)
9519 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9520 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9521 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9522
9523 /* Define global attributes... */
9524 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9525 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9526
9527 /* End definitions... */
9528 NC(nc_enddef(ncid));
9529
9530 /* Write data... */
9531 NC_PUT_DOUBLE("time", atm->time, 0);
9532 NC_PUT_DOUBLE("LAT", atm->lat, 0);
9533 NC_PUT_DOUBLE("LON", atm->lon, 0);
9534 NC_PUT_DOUBLE("PRESS", atm->p, 0);
9535 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
9536 for (int iq = 0; iq < ctl->nq; iq++)
9537 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9538
9539 /* Close file... */
9540 NC(nc_close(ncid));
9541}
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1223
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1056
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1137

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

9549 {
9550
9551 /* Global Counter... */
9552 static size_t out_cnt = 0;
9553
9554 double r, r_start, r_stop;
9555 int year, mon, day, hour, min, sec;
9556 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
9557 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
9558 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
9559
9560 int ncid, varid, tid, pid, cid;
9561 int dim_ids[2];
9562
9563 /* time, nparc */
9564 size_t start[2];
9565 size_t count[2];
9566
9567 /* Determine start and stop times of calculation... */
9568 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9569 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
9570 &min_start, &sec_start, &r_start);
9571 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
9572 &min_stop, &sec_stop, &r_stop);
9573
9574 sprintf(filename_out, "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc",
9575 dirname,
9576 year_start % 100, mon_start, day_start, hour_start,
9577 year_stop % 100, mon_stop, day_stop, hour_stop);
9578 LOG(1, "Write traj file: %s", filename_out);
9579
9580 /* Define hyperslap for the traj_file... */
9581 start[0] = out_cnt;
9582 start[1] = 0;
9583 count[0] = 1;
9584 count[1] = (size_t) atm->np;
9585
9586 /* Create the file at the first timestep... */
9587 if (out_cnt == 0) {
9588
9589 /* Create file... */
9590 nc_create(filename_out, NC_NETCDF4, &ncid);
9591
9592 /* Define dimensions... */
9593 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
9594 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9595 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
9596 dim_ids[0] = tid;
9597 dim_ids[1] = pid;
9598
9599 /* Define variables and their attributes... */
9600 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9601 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9602 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
9603 ctl->atm_nc_level, 0);
9604 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
9605 ctl->atm_nc_level, 0);
9606 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
9607 ctl->atm_nc_level, 0);
9608 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
9609 ctl->atm_nc_level, 0);
9610 for (int iq = 0; iq < ctl->nq; iq++)
9611 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9612 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9613 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9614
9615 /* Define global attributes... */
9616 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9617 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9618
9619 /* End definitions... */
9620 NC(nc_enddef(ncid));
9621 NC(nc_close(ncid));
9622 }
9623
9624 /* Increment global counter to change hyperslap... */
9625 out_cnt++;
9626
9627 /* Open file... */
9628 NC(nc_open(filename_out, NC_WRITE, &ncid));
9629
9630 /* Write data... */
9631 NC_PUT_DOUBLE("time", atm->time, 1);
9632 NC_PUT_DOUBLE("LAT", atm->lat, 1);
9633 NC_PUT_DOUBLE("LON", atm->lon, 1);
9634 NC_PUT_DOUBLE("PRESS", atm->p, 1);
9635 if (ctl->advect_vert_coord == 1) {
9636 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
9637 } else if (ctl->qnt_zeta >= 0) {
9638 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
9639 }
9640 for (int iq = 0; iq < ctl->nq; iq++)
9641 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
9642
9643 /* Close file... */
9644 NC(nc_close(ncid));
9645
9646 /* At the last time step create the init_fix_YYYYMMDDHH file... */
9647 if ((year == year_stop) && (mon == mon_stop)
9648 && (day == day_stop) && (hour == hour_stop)) {
9649
9650 /* Set filename... */
9651 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
9652 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
9653 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
9654 LOG(1, "Write init file: %s", filename_init);
9655
9656 /* Create file... */
9657 nc_create(filename_init, NC_NETCDF4, &ncid);
9658
9659 /* Define dimensions... */
9660 NC(nc_def_dim(ncid, "time", 1, &tid));
9661 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9662 dim_ids[0] = tid;
9663 dim_ids[1] = pid;
9664
9665 /* Define variables and their attributes... */
9666 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9667 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9668 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
9669 ctl->atm_nc_level, 0);
9670 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
9671 ctl->atm_nc_level, 0);
9672 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
9673 ctl->atm_nc_level, 0);
9674 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
9675 for (int iq = 0; iq < ctl->nq; iq++)
9676 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9677 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9678 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9679
9680 /* Define global attributes... */
9681 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9682 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9683
9684 /* End definitions... */
9685 NC(nc_enddef(ncid));
9686
9687 /* Write data... */
9688 NC_PUT_DOUBLE("time", atm->time, 0);
9689 NC_PUT_DOUBLE("LAT", atm->lat, 0);
9690 NC_PUT_DOUBLE("LON", atm->lon, 0);
9691 NC_PUT_DOUBLE("PRESS", atm->p, 0);
9692 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
9693 for (int iq = 0; iq < ctl->nq; iq++)
9694 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9695
9696 /* Close file... */
9697 NC(nc_close(ncid));
9698 }
9699}
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 9703 of file mptrac.c.

9706 {
9707
9708 int ncid, obsid, varid;
9709
9710 size_t start[2], count[2];
9711
9712 /* Create file... */
9713 NC(nc_create(filename, NC_NETCDF4, &ncid));
9714
9715 /* Define dimensions... */
9716 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
9717
9718 /* Define variables and their attributes... */
9719 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
9720 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9721 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
9722 ctl->atm_nc_level, 0);
9723 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
9724 ctl->atm_nc_level, 0);
9725 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
9726 ctl->atm_nc_level, 0);
9727 for (int iq = 0; iq < ctl->nq; iq++)
9728 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
9729 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
9730 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9731
9732 /* Define global attributes... */
9733 NC_PUT_ATT_GLOBAL("featureType", "point");
9734
9735 /* End definitions... */
9736 NC(nc_enddef(ncid));
9737
9738 /* Write data... */
9739 NC_PUT_DOUBLE("time", atm->time, 0);
9740 NC_PUT_DOUBLE("press", atm->p, 0);
9741 NC_PUT_DOUBLE("lon", atm->lon, 0);
9742 NC_PUT_DOUBLE("lat", atm->lat, 0);
9743 for (int iq = 0; iq < ctl->nq; iq++)
9744 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9745
9746 /* Close file... */
9747 NC(nc_close(ncid));
9748}

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

9756 {
9757
9758 static FILE *out;
9759
9760 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
9761 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
9762
9763 static int *obscount, ct, cx, cy, cz, ip, ix, iy, iz, n, nobs, nk;
9764
9765 /* Set timer... */
9766 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
9767
9768 /* Init... */
9769 if (t == ctl->t_start) {
9770
9771 /* Check quantity index for mass... */
9772 if (ctl->qnt_m < 0)
9773 ERRMSG("Need quantity mass!");
9774
9775 /* Allocate... */
9776 ALLOC(area, double,
9777 ctl->csi_ny);
9778 ALLOC(rt, double,
9779 NOBS);
9780 ALLOC(rz, double,
9781 NOBS);
9782 ALLOC(rlon, double,
9783 NOBS);
9784 ALLOC(rlat, double,
9785 NOBS);
9786 ALLOC(robs, double,
9787 NOBS);
9788
9789 /* Read observation data... */
9790 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
9791
9792 /* Read kernel data... */
9793 if (ctl->csi_kernel[0] != '-')
9794 read_kernel(ctl->csi_kernel, kz, kw, &nk);
9795
9796 /* Create new file... */
9797 LOG(1, "Write CSI data: %s", filename);
9798 if (!(out = fopen(filename, "w")))
9799 ERRMSG("Cannot create file!");
9800
9801 /* Write header... */
9802 fprintf(out,
9803 "# $1 = time [s]\n"
9804 "# $2 = number of hits (cx)\n"
9805 "# $3 = number of misses (cy)\n"
9806 "# $4 = number of false alarms (cz)\n"
9807 "# $5 = number of observations (cx + cy)\n"
9808 "# $6 = number of forecasts (cx + cz)\n"
9809 "# $7 = bias (ratio of forecasts and observations) [%%]\n"
9810 "# $8 = probability of detection (POD) [%%]\n"
9811 "# $9 = false alarm rate (FAR) [%%]\n"
9812 "# $10 = critical success index (CSI) [%%]\n");
9813 fprintf(out,
9814 "# $11 = hits associated with random chance\n"
9815 "# $12 = equitable threat score (ETS) [%%]\n"
9816 "# $13 = Pearson linear correlation coefficient\n"
9817 "# $14 = Spearman rank-order correlation coefficient\n"
9818 "# $15 = column density mean error (F - O) [kg/m^2]\n"
9819 "# $16 = column density root mean square error (RMSE) [kg/m^2]\n"
9820 "# $17 = column density mean absolute error [kg/m^2]\n"
9821 "# $18 = log-likelihood function\n"
9822 "# $19 = number of data points\n\n");
9823
9824 /* Set grid box size... */
9825 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
9826 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
9827 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
9828
9829 /* Set horizontal coordinates... */
9830 for (iy = 0; iy < ctl->csi_ny; iy++) {
9831 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
9832 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat));
9833 }
9834 }
9835
9836 /* Set time interval... */
9837 const double t0 = t - 0.5 * ctl->dt_mod;
9838 const double t1 = t + 0.5 * ctl->dt_mod;
9839
9840 /* Allocate... */
9841 ALLOC(modmean, double,
9842 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9843 ALLOC(obsmean, double,
9844 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9845 ALLOC(obscount, int,
9846 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9847 ALLOC(obsstd, double,
9848 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9849
9850 /* Loop over observations... */
9851 for (int i = 0; i < nobs; i++) {
9852
9853 /* Check time... */
9854 if (rt[i] < t0)
9855 continue;
9856 else if (rt[i] >= t1)
9857 break;
9858
9859 /* Check observation data... */
9860 if (!isfinite(robs[i]))
9861 continue;
9862
9863 /* Calculate indices... */
9864 ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
9865 iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
9866 iz = (int) ((rz[i] - ctl->csi_z0) / dz);
9867
9868 /* Check indices... */
9869 if (ix < 0 || ix >= ctl->csi_nx ||
9870 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9871 continue;
9872
9873 /* Get mean observation index... */
9874 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9875 obsmean[idx] += robs[i];
9876 obsstd[idx] += SQR(robs[i]);
9877 obscount[idx]++;
9878 }
9879
9880 /* Analyze model data... */
9881 for (ip = 0; ip < atm->np; ip++) {
9882
9883 /* Check time... */
9884 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9885 continue;
9886
9887 /* Get indices... */
9888 ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
9889 iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
9890 iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
9891
9892 /* Check indices... */
9893 if (ix < 0 || ix >= ctl->csi_nx ||
9894 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9895 continue;
9896
9897 /* Get total mass in grid cell... */
9898 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9899 modmean[idx] += kernel_weight(kz, kw, nk, atm->p[ip])
9900 * atm->q[ctl->qnt_m][ip];
9901 }
9902
9903 /* Analyze all grid cells... */
9904 for (ix = 0; ix < ctl->csi_nx; ix++)
9905 for (iy = 0; iy < ctl->csi_ny; iy++)
9906 for (iz = 0; iz < ctl->csi_nz; iz++) {
9907
9908 /* Calculate mean observation index... */
9909 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9910 if (obscount[idx] > 0) {
9911 obsmean[idx] /= obscount[idx];
9912 obsstd[idx] -= SQR(obsmean[idx]);
9913 obsstd[idx] = sqrt(obsstd[idx]);
9914 }
9915
9916 /* Calculate column density... */
9917 if (modmean[idx] > 0)
9918 modmean[idx] /= (1e6 * area[iy]);
9919
9920 /* Calculate CSI... */
9921 if (obscount[idx] > 0) {
9922 ct++;
9923 if (obsmean[idx] >= ctl->csi_obsmin &&
9924 modmean[idx] >= ctl->csi_modmin)
9925 cx++;
9926 else if (obsmean[idx] >= ctl->csi_obsmin &&
9927 modmean[idx] < ctl->csi_modmin)
9928 cy++;
9929 else if (obsmean[idx] < ctl->csi_obsmin &&
9930 modmean[idx] >= ctl->csi_modmin)
9931 cz++;
9932 }
9933
9934 /* Save data for other verification statistics... */
9935 if (obscount[idx] > 0
9936 && (obsmean[idx] >= ctl->csi_obsmin
9937 || modmean[idx] >= ctl->csi_modmin)) {
9938 x[n] = modmean[idx];
9939 y[n] = obsmean[idx];
9940 if (modmean[idx] >= ctl->csi_modmin)
9941 obsstdn[n] = obsstd[idx];
9942 if ((++n) >= NCSI)
9943 ERRMSG("Too many data points to calculate statistics!");
9944 }
9945 }
9946
9947 /* Write output... */
9948 if (fmod(t, ctl->csi_dt_out) == 0) {
9949
9950 /* Calculate verification statistics
9951 (https://www.cawcr.gov.au/projects/verification/) ... */
9952 static double work[2 * NCSI], work2[2 * NCSI];;
9953 const int n_obs = cx + cy;
9954 const int n_for = cx + cz;
9955 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
9956 const double pod = (n_obs > 0) ? (100. * cx) / n_obs : NAN;
9957 const double far = (n_for > 0) ? (100. * cz) / n_for : NAN;
9958 const double csi =
9959 (cx + cy + cz > 0) ? (100. * cx) / (cx + cy + cz) : NAN;
9960 const double cx_rd = (ct > 0) ? (1. * n_obs * n_for) / ct : NAN;
9961 const double ets = (cx + cy + cz - cx_rd > 0) ?
9962 (100. * (cx - cx_rd)) / (cx + cy + cz - cx_rd) : NAN;
9963 const double rho_p =
9964 (n > 0) ? gsl_stats_correlation(x, 1, y, 1, (size_t) n) : NAN;
9965 const double rho_s =
9966 (n > 0) ? gsl_stats_spearman(x, 1, y, 1, (size_t) n, work) : NAN;
9967 for (int i = 0; i < n; i++) {
9968 work[i] = x[i] - y[i];
9969 work2[i] = (obsstdn[i] != 0) ? (x[i] - y[i]) / obsstdn[i] : 0;
9970 }
9971 const double mean = (n > 0) ? gsl_stats_mean(work, 1, (size_t) n) : NAN;
9972 const double rmse =
9973 (n > 0) ? gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n,
9974 0.0) : NAN;
9975 const double absdev =
9976 (n > 0) ? gsl_stats_absdev_m(work, 1, (size_t) n, 0.0) : NAN;
9977 const double loglikelihood =
9978 (n > 0) ? gsl_stats_tss(work2, 1, (size_t) n) * (-0.5) : GSL_NAN;
9979
9980 /* Write... */
9981 fprintf(out,
9982 "%.2f %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n", t,
9983 cx, cy, cz, n_obs, n_for, bias, pod, far, csi, cx_rd, ets, rho_p,
9984 rho_s, mean, rmse, absdev, loglikelihood, n);
9985
9986 /* Set counters to zero... */
9987 n = ct = cx = cy = cz = 0;
9988 }
9989
9990 /* Free... */
9991 free(modmean);
9992 free(obsmean);
9993 free(obscount);
9994 free(obsstd);
9995
9996 /* Finalize... */
9997 if (t == ctl->t_stop) {
9998
9999 /* Close output file... */
10000 fclose(out);
10001
10002 /* Free... */
10003 free(area);
10004 free(rt);
10005 free(rz);
10006 free(rlon);
10007 free(rlat);
10008 free(robs);
10009 }
10010}
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:8888
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:6418
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:1773
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:267
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 10014 of file mptrac.c.

10018 {
10019
10020 static FILE *out;
10021
10022 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
10023 x[3], zm[NENS];
10024
10025 static int n[NENS];
10026
10027 /* Set timer... */
10028 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
10029
10030 /* Check quantities... */
10031 if (ctl->qnt_ens < 0)
10032 ERRMSG("Missing ensemble IDs!");
10033
10034 /* Set time interval... */
10035 const double t0 = t - 0.5 * ctl->dt_mod;
10036 const double t1 = t + 0.5 * ctl->dt_mod;
10037
10038 /* Init... */
10039 for (int i = 0; i < NENS; i++) {
10040 for (int iq = 0; iq < ctl->nq; iq++)
10041 qm[iq][i] = qs[iq][i] = 0;
10042 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
10043 n[i] = 0;
10044 }
10045
10046 /* Loop over air parcels... */
10047 for (int ip = 0; ip < atm->np; ip++) {
10048
10049 /* Check time... */
10050 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10051 continue;
10052
10053 /* Check ensemble ID... */
10054 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
10055 ERRMSG("Ensemble ID is out of range!");
10056
10057 /* Get means... */
10058 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
10059 for (int iq = 0; iq < ctl->nq; iq++) {
10060 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
10061 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
10062 }
10063 xm[ctl->qnt_ens][0] += x[0];
10064 xm[ctl->qnt_ens][1] += x[1];
10065 xm[ctl->qnt_ens][2] += x[2];
10066 zm[ctl->qnt_ens] += Z(atm->p[ip]);
10067 n[ctl->qnt_ens]++;
10068 }
10069
10070 /* Create file... */
10071 LOG(1, "Write ensemble data: %s", filename);
10072 if (!(out = fopen(filename, "w")))
10073 ERRMSG("Cannot create file!");
10074
10075 /* Write header... */
10076 fprintf(out,
10077 "# $1 = time [s]\n"
10078 "# $2 = altitude [km]\n"
10079 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
10080 for (int iq = 0; iq < ctl->nq; iq++)
10081 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
10082 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10083 for (int iq = 0; iq < ctl->nq; iq++)
10084 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
10085 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10086 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
10087
10088 /* Write data... */
10089 for (int i = 0; i < NENS; i++)
10090 if (n[i] > 0) {
10091 cart2geo(xm[i], &dummy, &lon, &lat);
10092 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
10093 for (int iq = 0; iq < ctl->nq; iq++) {
10094 fprintf(out, " ");
10095 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
10096 }
10097 for (int iq = 0; iq < ctl->nq; iq++) {
10098 fprintf(out, " ");
10099 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
10100 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
10101 }
10102 fprintf(out, " %d\n", n[i]);
10103 }
10104
10105 /* Close file... */
10106 fclose(out);
10107}
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:287
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 10111 of file mptrac.c.

10117 {
10118
10119 static double kz[EP], kw[EP];
10120
10121 static int nk;
10122
10123 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
10124
10125 int *ixs, *iys, *izs, *np;
10126
10127 /* Set timer... */
10128 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
10129
10130 /* Write info... */
10131 LOG(1, "Write grid data: %s", filename);
10132
10133 /* Init... */
10134 if (t == ctl->t_start) {
10135
10136 /* Read kernel data... */
10137 if (ctl->grid_kernel[0] != '-')
10138 read_kernel(ctl->grid_kernel, kz, kw, &nk);
10139 }
10140
10141 /* Allocate... */
10142 ALLOC(cd, double,
10143 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10144 for (int iq = 0; iq < ctl->nq; iq++) {
10145 ALLOC(mean[iq], double,
10146 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10147 ALLOC(sigma[iq], double,
10148 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10149 }
10150 ALLOC(vmr_impl, double,
10151 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10152 ALLOC(z, double,
10153 ctl->grid_nz);
10154 ALLOC(lon, double,
10155 ctl->grid_nx);
10156 ALLOC(lat, double,
10157 ctl->grid_ny);
10158 ALLOC(area, double,
10159 ctl->grid_ny);
10160 ALLOC(press, double,
10161 ctl->grid_nz);
10162 ALLOC(np, int,
10163 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10164 ALLOC(ixs, int,
10165 atm->np);
10166 ALLOC(iys, int,
10167 atm->np);
10168 ALLOC(izs, int,
10169 atm->np);
10170
10171 /* Set grid box size... */
10172 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
10173 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
10174 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
10175
10176 /* Set vertical coordinates... */
10177#pragma omp parallel for default(shared)
10178 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10179 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
10180 press[iz] = P(z[iz]);
10181 }
10182
10183 /* Set horizontal coordinates... */
10184 for (int ix = 0; ix < ctl->grid_nx; ix++)
10185 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
10186#pragma omp parallel for default(shared)
10187 for (int iy = 0; iy < ctl->grid_ny; iy++) {
10188 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
10189 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
10190 }
10191
10192 /* Set time interval for output... */
10193 const double t0 = t - 0.5 * ctl->dt_mod;
10194 const double t1 = t + 0.5 * ctl->dt_mod;
10195
10196 /* Get grid box indices... */
10197#pragma omp parallel for default(shared)
10198 for (int ip = 0; ip < atm->np; ip++) {
10199 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
10200 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
10201 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
10202 if (atm->time[ip] < t0 || atm->time[ip] > t1
10203 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
10204 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
10205 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
10206 izs[ip] = -1;
10207 }
10208
10209 /* Average data... */
10210 for (int ip = 0; ip < atm->np; ip++)
10211 if (izs[ip] >= 0) {
10212 int idx =
10213 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
10214 double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
10215 np[idx]++;
10216 for (int iq = 0; iq < ctl->nq; iq++) {
10217 mean[iq][idx] += kernel * atm->q[iq][ip];
10218 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
10219 }
10220 }
10221
10222 /* Calculate column density and volume mixing ratio... */
10223#pragma omp parallel for default(shared)
10224 for (int ix = 0; ix < ctl->grid_nx; ix++)
10225 for (int iy = 0; iy < ctl->grid_ny; iy++)
10226 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10227
10228 /* Get grid index... */
10229 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
10230
10231 /* Calculate column density... */
10232 cd[idx] = NAN;
10233 if (ctl->qnt_m >= 0)
10234 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
10235
10236 /* Calculate volume mixing ratio (implicit)... */
10237 vmr_impl[idx] = NAN;
10238 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
10239 && met1 != NULL) {
10240 vmr_impl[idx] = 0;
10241 if (mean[ctl->qnt_m][idx] > 0) {
10242
10243 /* Get temperature... */
10244 double temp;
10246 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
10247 lon[ix], lat[iy], &temp, ci, cw, 1);
10248
10249 /* Calculate volume mixing ratio... */
10250 vmr_impl[idx] =
10251 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
10252 }
10253 }
10254
10255 /* Calculate mean... */
10256 if (np[idx] > 0)
10257 for (int iq = 0; iq < ctl->nq; iq++) {
10258 mean[iq][idx] /= np[idx];
10259 double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
10260 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
10261 } else
10262 for (int iq = 0; iq < ctl->nq; iq++) {
10263 mean[iq][idx] = NAN;
10264 sigma[iq][idx] = NAN;
10265 }
10266 }
10267
10268 /* Write ASCII data... */
10269 if (ctl->grid_type == 0)
10270 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
10271 t, z, lon, lat, area, dz, np);
10272
10273 /* Write netCDF data... */
10274 else if (ctl->grid_type == 1)
10275 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
10276 t, z, lon, lat, area, dz, np);
10277
10278 /* Error message... */
10279 else
10280 ERRMSG("Grid data format GRID_TYPE unknown!");
10281
10282 /* Free... */
10283 free(cd);
10284 for (int iq = 0; iq < ctl->nq; iq++) {
10285 free(mean[iq]);
10286 free(sigma[iq]);
10287 }
10288 free(vmr_impl);
10289 free(z);
10290 free(lon);
10291 free(lat);
10292 free(area);
10293 free(press);
10294 free(np);
10295 free(ixs);
10296 free(iys);
10297 free(izs);
10298}
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:10302
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:10406
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 10302 of file mptrac.c.

10315 {
10316
10317 FILE *out;
10318
10319 /* Check if gnuplot output is requested... */
10320 if (ctl->grid_gpfile[0] != '-') {
10321
10322 /* Create gnuplot pipe... */
10323 if (!(out = popen("gnuplot", "w")))
10324 ERRMSG("Cannot create pipe to gnuplot!");
10325
10326 /* Set plot filename... */
10327 fprintf(out, "set out \"%s.png\"\n", filename);
10328
10329 /* Set time string... */
10330 double r;
10331 int year, mon, day, hour, min, sec;
10332 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
10333 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
10334 year, mon, day, hour, min);
10335
10336 /* Dump gnuplot file to pipe... */
10337 FILE *in;
10338 char line[LEN];
10339 if (!(in = fopen(ctl->grid_gpfile, "r")))
10340 ERRMSG("Cannot open file!");
10341 while (fgets(line, LEN, in))
10342 fprintf(out, "%s", line);
10343 fclose(in);
10344 }
10345
10346 else {
10347
10348 /* Create file... */
10349 if (!(out = fopen(filename, "w")))
10350 ERRMSG("Cannot create file!");
10351 }
10352
10353 /* Write header... */
10354 fprintf(out,
10355 "# $1 = time [s]\n"
10356 "# $2 = altitude [km]\n"
10357 "# $3 = longitude [deg]\n"
10358 "# $4 = latitude [deg]\n"
10359 "# $5 = surface area [km^2]\n"
10360 "# $6 = layer depth [km]\n"
10361 "# $7 = column density (implicit) [kg/m^2]\n"
10362 "# $8 = volume mixing ratio (implicit) [ppv]\n"
10363 "# $9 = number of particles [1]\n");
10364 for (int iq = 0; iq < ctl->nq; iq++)
10365 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
10366 ctl->qnt_unit[iq]);
10367 if (ctl->grid_stddev)
10368 for (int iq = 0; iq < ctl->nq; iq++)
10369 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
10370 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10371 fprintf(out, "\n");
10372
10373 /* Write data... */
10374 for (int ix = 0; ix < ctl->grid_nx; ix++) {
10375 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
10376 fprintf(out, "\n");
10377 for (int iy = 0; iy < ctl->grid_ny; iy++) {
10378 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
10379 fprintf(out, "\n");
10380 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10381 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
10382 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
10383 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
10384 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
10385 for (int iq = 0; iq < ctl->nq; iq++) {
10386 fprintf(out, " ");
10387 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
10388 }
10389 if (ctl->grid_stddev)
10390 for (int iq = 0; iq < ctl->nq; iq++) {
10391 fprintf(out, " ");
10392 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
10393 }
10394 fprintf(out, "\n");
10395 }
10396 }
10397 }
10398 }
10399
10400 /* Close file... */
10401 fclose(out);
10402}
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 10406 of file mptrac.c.

10419 {
10420
10421 char longname[2 * LEN], varname[2 * LEN];
10422
10423 double *help;
10424
10425 int *help2, ncid, dimid[10], varid;
10426
10427 size_t start[2], count[2];
10428
10429 /* Allocate... */
10430 ALLOC(help, double,
10431 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10432 ALLOC(help2, int,
10433 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10434
10435 /* Create file... */
10436 NC(nc_create(filename, NC_NETCDF4, &ncid));
10437
10438 /* Define dimensions... */
10439 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
10440 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
10441 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
10442 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
10443 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
10444
10445 /* Define variables and their attributes... */
10446 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
10447 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
10448 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
10449 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
10450 0);
10451 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
10452 0);
10453 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
10454 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
10455
10456 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
10457 ctl->grid_nc_level, 0);
10458 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid, "volume mixing ratio (implicit)",
10459 "ppv", ctl->grid_nc_level, 0);
10460 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
10461 for (int iq = 0; iq < ctl->nq; iq++) {
10462 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
10463 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
10464 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
10465 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
10466 if (ctl->grid_stddev) {
10467 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
10468 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
10469 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
10470 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
10471 }
10472 }
10473 /* End definitions... */
10474 NC(nc_enddef(ncid));
10475
10476 /* Write data... */
10477 NC_PUT_DOUBLE("time", &t, 0);
10478 NC_PUT_DOUBLE("lon", lon, 0);
10479 NC_PUT_DOUBLE("lat", lat, 0);
10480 NC_PUT_DOUBLE("z", z, 0);
10481 NC_PUT_DOUBLE("area", area, 0);
10482 NC_PUT_DOUBLE("dz", &dz, 0);
10483
10484 for (int ix = 0; ix < ctl->grid_nx; ix++)
10485 for (int iy = 0; iy < ctl->grid_ny; iy++)
10486 for (int iz = 0; iz < ctl->grid_nz; iz++)
10487 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10488 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10489 NC_PUT_DOUBLE("cd", help, 0);
10490
10491 for (int ix = 0; ix < ctl->grid_nx; ix++)
10492 for (int iy = 0; iy < ctl->grid_ny; iy++)
10493 for (int iz = 0; iz < ctl->grid_nz; iz++)
10494 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10495 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10496 NC_PUT_DOUBLE("vmr_impl", help, 0);
10497
10498 for (int ix = 0; ix < ctl->grid_nx; ix++)
10499 for (int iy = 0; iy < ctl->grid_ny; iy++)
10500 for (int iz = 0; iz < ctl->grid_nz; iz++)
10501 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10502 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10503 NC_PUT_INT("np", help2, 0);
10504
10505 for (int iq = 0; iq < ctl->nq; iq++) {
10506 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
10507 for (int ix = 0; ix < ctl->grid_nx; ix++)
10508 for (int iy = 0; iy < ctl->grid_ny; iy++)
10509 for (int iz = 0; iz < ctl->grid_nz; iz++)
10510 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10511 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10512 NC_PUT_DOUBLE(varname, help, 0);
10513 }
10514
10515 if (ctl->grid_stddev)
10516 for (int iq = 0; iq < ctl->nq; iq++) {
10517 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
10518 for (int ix = 0; ix < ctl->grid_nx; ix++)
10519 for (int iy = 0; iy < ctl->grid_ny; iy++)
10520 for (int iz = 0; iz < ctl->grid_nz; iz++)
10521 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10522 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10523 NC_PUT_DOUBLE(varname, help, 0);
10524 }
10525
10526 /* Close file... */
10527 NC(nc_close(ncid));
10528
10529 /* Free... */
10530 free(help);
10531 free(help2);
10532}
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1184

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

10539 {
10540
10541 /* Create file... */
10542 FILE *out;
10543 if (!(out = fopen(filename, "w")))
10544 ERRMSG("Cannot create file!");
10545
10546 /* Write type of binary data... */
10547 FWRITE(&ctl->met_type, int,
10548 1,
10549 out);
10550
10551 /* Write version of binary data... */
10552 int version = 103;
10553 FWRITE(&version, int,
10554 1,
10555 out);
10556
10557 /* Write grid data... */
10558 FWRITE(&met->time, double,
10559 1,
10560 out);
10561 FWRITE(&met->nx, int,
10562 1,
10563 out);
10564 FWRITE(&met->ny, int,
10565 1,
10566 out);
10567 FWRITE(&met->np, int,
10568 1,
10569 out);
10570 FWRITE(met->lon, double,
10571 (size_t) met->nx,
10572 out);
10573 FWRITE(met->lat, double,
10574 (size_t) met->ny,
10575 out);
10576 FWRITE(met->p, double,
10577 (size_t) met->np,
10578 out);
10579
10580 /* Write surface data... */
10581 write_met_bin_2d(out, met, met->ps, "PS");
10582 write_met_bin_2d(out, met, met->ts, "TS");
10583 write_met_bin_2d(out, met, met->zs, "ZS");
10584 write_met_bin_2d(out, met, met->us, "US");
10585 write_met_bin_2d(out, met, met->vs, "VS");
10586 write_met_bin_2d(out, met, met->ess, "ESS");
10587 write_met_bin_2d(out, met, met->nss, "NSS");
10588 write_met_bin_2d(out, met, met->shf, "SHF");
10589 write_met_bin_2d(out, met, met->lsm, "LSM");
10590 write_met_bin_2d(out, met, met->sst, "SST");
10591 write_met_bin_2d(out, met, met->pbl, "PBL");
10592 write_met_bin_2d(out, met, met->pt, "PT");
10593 write_met_bin_2d(out, met, met->tt, "TT");
10594 write_met_bin_2d(out, met, met->zt, "ZT");
10595 write_met_bin_2d(out, met, met->h2ot, "H2OT");
10596 write_met_bin_2d(out, met, met->pct, "PCT");
10597 write_met_bin_2d(out, met, met->pcb, "PCB");
10598 write_met_bin_2d(out, met, met->cl, "CL");
10599 write_met_bin_2d(out, met, met->plcl, "PLCL");
10600 write_met_bin_2d(out, met, met->plfc, "PLFC");
10601 write_met_bin_2d(out, met, met->pel, "PEL");
10602 write_met_bin_2d(out, met, met->cape, "CAPE");
10603 write_met_bin_2d(out, met, met->cin, "CIN");
10604 write_met_bin_2d(out, met, met->o3c, "O3C");
10605
10606 /* Write level data... */
10607 write_met_bin_3d(out, ctl, met, met->z, "Z",
10608 (ctl->met_zfp_tol_z <= 0 ? ctl->met_zfp_prec : 0),
10609 ctl->met_zfp_tol_z);
10610 write_met_bin_3d(out, ctl, met, met->t, "T",
10611 (ctl->met_zfp_tol_t <= 0 ? ctl->met_zfp_prec : 0),
10612 ctl->met_zfp_tol_t);
10613 write_met_bin_3d(out, ctl, met, met->u, "U", ctl->met_zfp_prec, 0);
10614 write_met_bin_3d(out, ctl, met, met->v, "V", ctl->met_zfp_prec, 0);
10615 write_met_bin_3d(out, ctl, met, met->w, "W", ctl->met_zfp_prec, 0);
10616 write_met_bin_3d(out, ctl, met, met->pv, "PV", ctl->met_zfp_prec, 0);
10617 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", ctl->met_zfp_prec, 0);
10618 write_met_bin_3d(out, ctl, met, met->o3, "O3", ctl->met_zfp_prec, 0);
10619 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", ctl->met_zfp_prec, 0);
10620 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", ctl->met_zfp_prec, 0);
10621 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", ctl->met_zfp_prec, 0);
10622 write_met_bin_3d(out, ctl, met, met->swc, "SWC", ctl->met_zfp_prec, 0);
10623 write_met_bin_3d(out, ctl, met, met->cc, "CC", ctl->met_zfp_prec, 0);
10624
10625 /* Write final flag... */
10626 int final = 999;
10627 FWRITE(&final, int,
10628 1,
10629 out);
10630
10631 /* Close file... */
10632 fclose(out);
10633}
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:10666
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:10637
int met_zfp_prec
ZFP compression precision for all variables, except z and T.
Definition: mptrac.h:2512
double met_zfp_tol_t
ZFP compression tolerance for temperature.
Definition: mptrac.h:2515
double met_zfp_tol_z
ZFP compression tolerance for geopotential height.
Definition: mptrac.h:2518
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 10637 of file mptrac.c.

10641 {
10642
10643 float *help;
10644
10645 /* Allocate... */
10646 ALLOC(help, float,
10647 EX * EY);
10648
10649 /* Copy data... */
10650 for (int ix = 0; ix < met->nx; ix++)
10651 for (int iy = 0; iy < met->ny; iy++)
10652 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
10653
10654 /* Write uncompressed data... */
10655 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
10656 FWRITE(help, float,
10657 (size_t) (met->nx * met->ny),
10658 out);
10659
10660 /* Free... */
10661 free(help);
10662}

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

10673 {
10674
10675 float *help;
10676
10677 /* Allocate... */
10678 ALLOC(help, float,
10679 EX * EY * EP);
10680
10681 /* Copy data... */
10682#pragma omp parallel for default(shared) collapse(2)
10683 for (int ix = 0; ix < met->nx; ix++)
10684 for (int iy = 0; iy < met->ny; iy++)
10685 for (int ip = 0; ip < met->np; ip++)
10686 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
10687
10688 /* Write uncompressed data... */
10689 if (ctl->met_type == 1) {
10690 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
10691 FWRITE(help, float,
10692 (size_t) (met->nx * met->ny * met->np),
10693 out);
10694 }
10695
10696 /* Write packed data... */
10697 else if (ctl->met_type == 2)
10698 compress_pck(varname, help, (size_t) (met->ny * met->nx),
10699 (size_t) met->np, 0, out);
10700
10701 /* Write zfp data... */
10702#ifdef ZFP
10703 else if (ctl->met_type == 3) {
10704 FWRITE(&precision, int,
10705 1,
10706 out);
10707 FWRITE(&tolerance, double,
10708 1,
10709 out);
10710 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
10711 tolerance, 0, out);
10712 }
10713#endif
10714
10715 /* Write zstd data... */
10716#ifdef ZSTD
10717 else if (ctl->met_type == 4)
10718 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
10719 ctl->met_zstd_level, out);
10720#endif
10721
10722 /* Write cmultiscale data... */
10723#ifdef CMS
10724 else if (ctl->met_type == 5) {
10725 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
10726 (size_t) met->np, 0, out);
10727 }
10728#endif
10729
10730 /* Unknown method... */
10731 else {
10732 ERRMSG("MET_TYPE not supported!");
10733 LOG(3, "%d %g", precision, tolerance);
10734 }
10735
10736 /* Free... */
10737 free(help);
10738}
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 10742 of file mptrac.c.

10745 {
10746
10747 /* Create file... */
10748 int ncid, varid;
10749 size_t start[4], count[4];
10750 nc_create(filename, NC_NETCDF4, &ncid);
10751
10752 /* Define dimensions... */
10753 int tid, lonid, latid, levid;
10754 NC(nc_def_dim(ncid, "time", 1, &tid));
10755 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
10756 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
10757 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
10758
10759 /* Define grid... */
10760 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
10761 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
10762 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
10763 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
10764 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
10765
10766 /* Define surface variables... */
10767 int dimid2[2] = { latid, lonid };
10768 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
10769 ctl->met_nc_level, 0);
10770 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
10771 ctl->met_nc_level, 0);
10772 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
10773 ctl->met_nc_level, 0);
10774 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
10775 "m s**-1", ctl->met_nc_level, 0);
10776 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
10777 "m s**-1", ctl->met_nc_level, 0);
10778 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
10779 "Instantaneous eastward turbulent surface stress", "N m**-2",
10780 ctl->met_nc_level, 0);
10781 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
10782 "Instantaneous northward turbulent surface stress", "N m**-2",
10783 ctl->met_nc_level, 0);
10784 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
10785 "Instantaneous surface sensible heat flux", "W m**-1",
10786 ctl->met_nc_level, 0);
10787 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
10788 ctl->met_nc_level, 0);
10789 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
10790 ctl->met_nc_level, 0);
10791 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
10792 ctl->met_nc_level, 0);
10793 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
10794 ctl->met_nc_level, 0);
10795 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
10796 ctl->met_nc_level, 0);
10797 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
10798 ctl->met_nc_level, 0);
10799 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
10800 ctl->met_nc_level, 0);
10801 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
10802 ctl->met_nc_level, 0);
10803 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
10804 ctl->met_nc_level, 0);
10805 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water", "kg m**2",
10806 ctl->met_nc_level, 0);
10807 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
10808 "Pressure at lifted condensation level (LCL)", "Pa",
10809 ctl->met_nc_level, 0);
10810 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
10811 "Pressure at level of free convection (LFC)", "Pa",
10812 ctl->met_nc_level, 0);
10813 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2, "Pressure at equilibrium level (EL)",
10814 "Pa", ctl->met_nc_level, 0);
10815 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
10816 "Convective available potential energy", "J kg**-1",
10817 ctl->met_nc_level, 0);
10818 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition", "J kg**-1",
10819 ctl->met_nc_level, 0);
10820 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
10821 ctl->met_nc_level, 0);
10822
10823 /* Define level data... */
10824 int dimid3[3] = { levid, latid, lonid };
10825 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
10826 ctl->met_nc_level, ctl->met_nc_quant);
10827 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
10828 ctl->met_nc_level, ctl->met_nc_quant);
10829 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
10830 ctl->met_nc_level, ctl->met_nc_quant);
10831 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
10832 ctl->met_nc_level, ctl->met_nc_quant);
10833 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
10834 ctl->met_nc_level, ctl->met_nc_quant);
10835 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
10836 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10837 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
10838 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10839 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
10840 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10841 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
10842 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10843 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
10844 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10845 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
10846 ctl->met_nc_level, ctl->met_nc_quant);
10847
10848 /* End definitions... */
10849 NC(nc_enddef(ncid));
10850
10851 /* Write grid data... */
10852 NC_PUT_DOUBLE("time", &met->time, 0);
10853 NC_PUT_DOUBLE("lon", met->lon, 0);
10854 NC_PUT_DOUBLE("lat", met->lat, 0);
10855 double phelp[EP];
10856 for (int ip = 0; ip < met->np; ip++)
10857 phelp[ip] = 100. * met->p[ip];
10858 NC_PUT_DOUBLE("lev", phelp, 0);
10859
10860 /* Write surface data... */
10861 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
10862 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
10863 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
10864 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
10865 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
10866 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
10867 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
10868 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
10869 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
10870 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
10871 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
10872 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
10873 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
10874 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
10875 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
10876 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
10877 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
10878 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
10879 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
10880 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
10881 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
10882 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
10883 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
10884 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
10885
10886 /* Write level data... */
10887 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
10888 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
10889 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
10890 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
10891 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
10892 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
10893 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
10894 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
10895 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
10896 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
10897 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
10898
10899 /* Close file... */
10900 NC(nc_close(ncid));
10901}
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:10905
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:10934
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2506
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2503
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 10905 of file mptrac.c.

10910 {
10911
10912 int varid;
10913 size_t start[4], count[4];
10914
10915 /* Allocate... */
10916 float *help;
10917 ALLOC(help, float,
10918 EX * EY);
10919
10920 /* Copy data... */
10921 for (int ix = 0; ix < met->nx; ix++)
10922 for (int iy = 0; iy < met->ny; iy++)
10923 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
10924
10925 /* Write data... */
10926 NC_PUT_FLOAT(varname, help, 0);
10927
10928 /* Free... */
10929 free(help);
10930}
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1161

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

10939 {
10940
10941 int varid;
10942 size_t start[4], count[4];
10943
10944 /* Allocate... */
10945 float *help;
10946 ALLOC(help, float,
10947 EX * EY * EP);
10948
10949 /* Copy data... */
10950 for (int ix = 0; ix < met->nx; ix++)
10951 for (int iy = 0; iy < met->ny; iy++)
10952 for (int ip = 0; ip < met->np; ip++)
10953 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
10954
10955 /* Write data... */
10956 NC_PUT_FLOAT(varname, help, 0);
10957
10958 /* Free... */
10959 free(help);
10960}

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

10970 {
10971
10972 static FILE *out;
10973
10974 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
10975 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
10976
10977 static int nobs, *obscount, ip, okay;
10978
10979 /* Set timer... */
10980 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
10981
10982 /* Init... */
10983 if (t == ctl->t_start) {
10984
10985 /* Check quantity index for mass... */
10986 if (ctl->qnt_m < 0)
10987 ERRMSG("Need quantity mass!");
10988
10989 /* Check molar mass... */
10990 if (ctl->molmass <= 0)
10991 ERRMSG("Specify molar mass!");
10992
10993 /* Allocate... */
10994 ALLOC(lon, double,
10995 ctl->prof_nx);
10996 ALLOC(lat, double,
10997 ctl->prof_ny);
10998 ALLOC(area, double,
10999 ctl->prof_ny);
11000 ALLOC(z, double,
11001 ctl->prof_nz);
11002 ALLOC(press, double,
11003 ctl->prof_nz);
11004 ALLOC(rt, double,
11005 NOBS);
11006 ALLOC(rz, double,
11007 NOBS);
11008 ALLOC(rlon, double,
11009 NOBS);
11010 ALLOC(rlat, double,
11011 NOBS);
11012 ALLOC(robs, double,
11013 NOBS);
11014
11015 /* Read observation data... */
11016 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11017
11018 /* Create new output file... */
11019 LOG(1, "Write profile data: %s", filename);
11020 if (!(out = fopen(filename, "w")))
11021 ERRMSG("Cannot create file!");
11022
11023 /* Write header... */
11024 fprintf(out,
11025 "# $1 = time [s]\n"
11026 "# $2 = altitude [km]\n"
11027 "# $3 = longitude [deg]\n"
11028 "# $4 = latitude [deg]\n"
11029 "# $5 = pressure [hPa]\n"
11030 "# $6 = temperature [K]\n"
11031 "# $7 = volume mixing ratio [ppv]\n"
11032 "# $8 = H2O volume mixing ratio [ppv]\n"
11033 "# $9 = O3 volume mixing ratio [ppv]\n"
11034 "# $10 = observed BT index [K]\n"
11035 "# $11 = number of observations\n");
11036
11037 /* Set grid box size... */
11038 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
11039 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
11040 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
11041
11042 /* Set vertical coordinates... */
11043 for (int iz = 0; iz < ctl->prof_nz; iz++) {
11044 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
11045 press[iz] = P(z[iz]);
11046 }
11047
11048 /* Set horizontal coordinates... */
11049 for (int ix = 0; ix < ctl->prof_nx; ix++)
11050 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
11051 for (int iy = 0; iy < ctl->prof_ny; iy++) {
11052 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
11053 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
11054 }
11055 }
11056
11057 /* Set time interval... */
11058 const double t0 = t - 0.5 * ctl->dt_mod;
11059 const double t1 = t + 0.5 * ctl->dt_mod;
11060
11061 /* Allocate... */
11062 ALLOC(mass, double,
11063 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
11064 ALLOC(obsmean, double,
11065 ctl->prof_nx * ctl->prof_ny);
11066 ALLOC(obscount, int,
11067 ctl->prof_nx * ctl->prof_ny);
11068
11069 /* Loop over observations... */
11070 for (int i = 0; i < nobs; i++) {
11071
11072 /* Check time... */
11073 if (rt[i] < t0)
11074 continue;
11075 else if (rt[i] >= t1)
11076 break;
11077
11078 /* Check observation data... */
11079 if (!isfinite(robs[i]))
11080 continue;
11081
11082 /* Calculate indices... */
11083 int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
11084 int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
11085
11086 /* Check indices... */
11087 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
11088 continue;
11089
11090 /* Get mean observation index... */
11091 int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
11092 obsmean[idx] += robs[i];
11093 obscount[idx]++;
11094 }
11095
11096 /* Analyze model data... */
11097 for (ip = 0; ip < atm->np; ip++) {
11098
11099 /* Check time... */
11100 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11101 continue;
11102
11103 /* Get indices... */
11104 int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
11105 int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
11106 int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
11107
11108 /* Check indices... */
11109 if (ix < 0 || ix >= ctl->prof_nx ||
11110 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
11111 continue;
11112
11113 /* Get total mass in grid cell... */
11114 int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11115 mass[idx] += atm->q[ctl->qnt_m][ip];
11116 }
11117
11118 /* Extract profiles... */
11119 for (int ix = 0; ix < ctl->prof_nx; ix++)
11120 for (int iy = 0; iy < ctl->prof_ny; iy++) {
11121 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
11122 if (obscount[idx2] > 0) {
11123
11124 /* Check profile... */
11125 okay = 0;
11126 for (int iz = 0; iz < ctl->prof_nz; iz++) {
11127 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11128 if (mass[idx3] > 0) {
11129 okay = 1;
11130 break;
11131 }
11132 }
11133 if (!okay)
11134 continue;
11135
11136 /* Write output... */
11137 fprintf(out, "\n");
11138
11139 /* Loop over altitudes... */
11140 for (int iz = 0; iz < ctl->prof_nz; iz++) {
11141
11142 /* Get temperature, water vapor, and ozone... */
11144 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
11145 lon[ix], lat[iy], &temp, ci, cw, 1);
11146 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
11147 lon[ix], lat[iy], &h2o, ci, cw, 0);
11148 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
11149 lon[ix], lat[iy], &o3, ci, cw, 0);
11150
11151 /* Calculate volume mixing ratio... */
11152 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11153 vmr = MA / ctl->molmass * mass[idx3]
11154 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
11155
11156 /* Write output... */
11157 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
11158 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
11159 obsmean[idx2] / obscount[idx2], obscount[idx2]);
11160 }
11161 }
11162 }
11163
11164 /* Free... */
11165 free(mass);
11166 free(obsmean);
11167 free(obscount);
11168
11169 /* Finalize... */
11170 if (t == ctl->t_stop) {
11171
11172 /* Close output file... */
11173 fclose(out);
11174
11175 /* Free... */
11176 free(lon);
11177 free(lat);
11178 free(area);
11179 free(z);
11180 free(press);
11181 free(rt);
11182 free(rz);
11183 free(rlon);
11184 free(rlat);
11185 free(robs);
11186 }
11187}
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 11191 of file mptrac.c.

11197 {
11198
11199 static FILE *out;
11200
11201 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
11202 kw[EP];
11203
11204 static int nobs, nk;
11205
11206 /* Set timer... */
11207 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
11208
11209 /* Init... */
11210 if (t == ctl->t_start) {
11211
11212 /* Allocate... */
11213 ALLOC(rt, double,
11214 NOBS);
11215 ALLOC(rz, double,
11216 NOBS);
11217 ALLOC(rlon, double,
11218 NOBS);
11219 ALLOC(rlat, double,
11220 NOBS);
11221 ALLOC(robs, double,
11222 NOBS);
11223
11224 /* Read observation data... */
11225 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11226
11227 /* Read kernel data... */
11228 if (ctl->sample_kernel[0] != '-')
11229 read_kernel(ctl->sample_kernel, kz, kw, &nk);
11230
11231 /* Create output file... */
11232 LOG(1, "Write sample data: %s", filename);
11233 if (!(out = fopen(filename, "w")))
11234 ERRMSG("Cannot create file!");
11235
11236 /* Write header... */
11237 fprintf(out,
11238 "# $1 = time [s]\n"
11239 "# $2 = altitude [km]\n"
11240 "# $3 = longitude [deg]\n"
11241 "# $4 = latitude [deg]\n"
11242 "# $5 = surface area [km^2]\n"
11243 "# $6 = layer depth [km]\n"
11244 "# $7 = number of particles [1]\n"
11245 "# $8 = column density [kg/m^2]\n"
11246 "# $9 = volume mixing ratio [ppv]\n"
11247 "# $10 = observed BT index [K]\n\n");
11248
11249 /* Set latitude range, squared radius, and area... */
11250 dlat = DY2DEG(ctl->sample_dx);
11251 rmax2 = SQR(ctl->sample_dx);
11252 area = M_PI * rmax2;
11253 }
11254
11255 /* Set time interval for output... */
11256 const double t0 = t - 0.5 * ctl->dt_mod;
11257 const double t1 = t + 0.5 * ctl->dt_mod;
11258
11259 /* Loop over observations... */
11260 for (int i = 0; i < nobs; i++) {
11261
11262 /* Check time... */
11263 if (rt[i] < t0)
11264 continue;
11265 else if (rt[i] >= t1)
11266 break;
11267
11268 /* Calculate Cartesian coordinates... */
11269 double x0[3];
11270 geo2cart(0, rlon[i], rlat[i], x0);
11271
11272 /* Set pressure range... */
11273 const double rp = P(rz[i]);
11274 const double ptop = P(rz[i] + ctl->sample_dz);
11275 const double pbot = P(rz[i] - ctl->sample_dz);
11276
11277 /* Init... */
11278 double mass = 0;
11279 int np = 0;
11280
11281 /* Loop over air parcels... */
11282 //#pragma omp parallel for default(shared) reduction(+:mass,np)
11283 for (int ip = 0; ip < atm->np; ip++) {
11284
11285 /* Check time... */
11286 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11287 continue;
11288
11289 /* Check latitude... */
11290 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
11291 continue;
11292
11293 /* Check horizontal distance... */
11294 double x1[3];
11295 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
11296 if (DIST2(x0, x1) > rmax2)
11297 continue;
11298
11299 /* Check pressure... */
11300 if (ctl->sample_dz > 0)
11301 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
11302 continue;
11303
11304 /* Add mass... */
11305 if (ctl->qnt_m >= 0)
11306 mass +=
11307 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11308 np++;
11309 }
11310
11311 /* Calculate column density... */
11312 const double cd = mass / (1e6 * area);
11313
11314 /* Calculate volume mixing ratio... */
11315 double vmr = 0;
11316 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
11317 if (mass > 0) {
11318
11319 /* Get temperature... */
11320 double temp;
11322 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
11323 rlon[i], rlat[i], &temp, ci, cw, 1);
11324
11325 /* Calculate volume mixing ratio... */
11326 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
11327 }
11328 } else
11329 vmr = NAN;
11330
11331 /* Write output... */
11332 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
11333 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
11334 }
11335
11336 /* Finalize...... */
11337 if (t == ctl->t_stop) {
11338
11339 /* Close output file... */
11340 fclose(out);
11341
11342 /* Free... */
11343 free(rt);
11344 free(rz);
11345 free(rlon);
11346 free(rlat);
11347 free(robs);
11348 }
11349}
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 11353 of file mptrac.c.

11357 {
11358
11359 static FILE *out;
11360
11361 static double rmax2, x0[3], x1[3];
11362
11363 /* Set timer... */
11364 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
11365
11366 /* Init... */
11367 if (t == ctl->t_start) {
11368
11369 /* Write info... */
11370 LOG(1, "Write station data: %s", filename);
11371
11372 /* Create new file... */
11373 if (!(out = fopen(filename, "w")))
11374 ERRMSG("Cannot create file!");
11375
11376 /* Write header... */
11377 fprintf(out,
11378 "# $1 = time [s]\n"
11379 "# $2 = altitude [km]\n"
11380 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11381 for (int iq = 0; iq < ctl->nq; iq++)
11382 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
11383 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11384 fprintf(out, "\n");
11385
11386 /* Set geolocation and search radius... */
11387 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
11388 rmax2 = SQR(ctl->stat_r);
11389 }
11390
11391 /* Set time interval for output... */
11392 const double t0 = t - 0.5 * ctl->dt_mod;
11393 const double t1 = t + 0.5 * ctl->dt_mod;
11394
11395 /* Loop over air parcels... */
11396 for (int ip = 0; ip < atm->np; ip++) {
11397
11398 /* Check time... */
11399 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11400 continue;
11401
11402 /* Check time range for station output... */
11403 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
11404 continue;
11405
11406 /* Check station flag... */
11407 if (ctl->qnt_stat >= 0)
11408 if ((int) atm->q[ctl->qnt_stat][ip])
11409 continue;
11410
11411 /* Get Cartesian coordinates... */
11412 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
11413
11414 /* Check horizontal distance... */
11415 if (DIST2(x0, x1) > rmax2)
11416 continue;
11417
11418 /* Set station flag... */
11419 if (ctl->qnt_stat >= 0)
11420 atm->q[ctl->qnt_stat][ip] = 1;
11421
11422 /* Write data... */
11423 fprintf(out, "%.2f %g %g %g",
11424 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
11425 for (int iq = 0; iq < ctl->nq; iq++) {
11426 fprintf(out, " ");
11427 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11428 }
11429 fprintf(out, "\n");
11430 }
11431
11432 /* Close file... */
11433 if (t == ctl->t_stop)
11434 fclose(out);
11435}
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 11439 of file mptrac.c.

11443 {
11444
11445 FILE *out;
11446
11447 /* Set timer... */
11448 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
11449
11450 /* Write info... */
11451 LOG(1, "Write VTK data: %s", filename);
11452
11453 /* Set time interval for output... */
11454 const double t0 = t - 0.5 * ctl->dt_mod;
11455 const double t1 = t + 0.5 * ctl->dt_mod;
11456
11457 /* Create file... */
11458 if (!(out = fopen(filename, "w")))
11459 ERRMSG("Cannot create file!");
11460
11461 /* Count data points... */
11462 int np = 0;
11463 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11464 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11465 continue;
11466 np++;
11467 }
11468
11469 /* Write header... */
11470 fprintf(out,
11471 "# vtk DataFile Version 3.0\n"
11472 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
11473
11474 /* Write point coordinates... */
11475 fprintf(out, "POINTS %d float\n", np);
11476 if (ctl->vtk_sphere) {
11477 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11478 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11479 continue;
11480 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
11481 + ctl->vtk_offset) / RE;
11482 const double coslat = cos(DEG2RAD(atm->lat[ip]));
11483 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
11484 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
11485 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
11486 fprintf(out, "%g %g %g\n", x, y, z);
11487 }
11488 } else
11489 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11490 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11491 continue;
11492 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
11493 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
11494 }
11495
11496 /* Write point data... */
11497 fprintf(out, "POINT_DATA %d\n", np);
11498 for (int iq = 0; iq < ctl->nq; iq++) {
11499 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
11500 ctl->qnt_name[iq]);
11501 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11502 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11503 continue;
11504 fprintf(out, "%g\n", atm->q[iq][ip]);
11505 }
11506 }
11507
11508 /* Close file... */
11509 fclose(out);
11510}