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_log_level (FILE *out, const char *codec, const char *varname, const size_t lev, const double plev, const double ratio, const double bpv, const double t_comp, const double t_decomp, const size_t n, const size_t nbytes, const float *org, const float *cmp)
 Write one row of per-level compression diagnostics. More...
 
void compress_log_levels_3d (FILE *out, const char *codec, const char *varname, const met_t *met, const float *org_all, const float *cmp_all, const size_t nxy, const size_t nz, const double ratio, const double bpv, const double t_comp, const double t_decomp, const size_t nbytes)
 Write per-level compression diagnostics for a full 3-D field. More...
 
void compress_scale_to_unit (float *array, const size_t nxy, const size_t nz, double *off, double *scl)
 Scales each vertical level of a 3-D field independently to the interval [0,1]. More...
 
void compress_unscale_from_unit (float *array, const size_t nxy, const size_t nz, const double *off, const double *scl)
 Restores a levelwise [0,1]-scaled 3-D field to physical units. More...
 
int compress_read_lossy_scale (FILE *in, const size_t nz, double **off, double **scl)
 Read optional lossyscaling metadata for a 3-D field. More...
 
void compress_write_lossy_scale (FILE *out, const int enabled, float *array, const size_t nxy, const size_t nz, double **off, double **scl)
 Write optional lossyscaling metadata for a 3-D field. More...
 
int compress_metvar_index (const char *varname)
 Maps a meteorological variable name to its internal MPTRAC variable index. More...
 
void compress_pck (const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
 Compresses or decompresses a 3‑D float array using the PCK format. More...
 
double cos_sza (const double sec, const double lon, const double lat)
 Calculates the cosine of the solar zenith angle. More...
 
void day2doy (const int year, const int mon, const int day, int *doy)
 Get day of year from date. More...
 
void doy2day (const int year, const int doy, int *mon, int *day)
 Converts a given day of the year (DOY) to a date (month and day). More...
 
void fft_help (double *fcReal, double *fcImag, const int n)
 Computes the Fast Fourier Transform (FFT) of a complex sequence. More...
 
void geo2cart (const double z, const double lon, const double lat, double *x)
 Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates. More...
 
void get_met_filename (const ctl_t *ctl, const double t, const int direct, const char *metbase, const double dt_met, char *filename)
 Generates a formatted filename for meteorological data files based on the input parameters. More...
 
void get_met_replace (char *orig, const char *search, const char *repl)
 Replaces occurrences of a substring in a string with another substring. More...
 
void get_tropo (const int met_tropo, ctl_t *ctl, const clim_t *clim, met_t *met, const double *lons, const int nx, const double *lats, const int ny, double *pt, double *zt, double *tt, double *qt, double *o3t, double *ps, double *zs)
 Calculate tropopause data. More...
 
void intpol_check_lon_lat (const double *lons, const int nlon, const double *lats, const int nlat, const double lon, const double lat, double *lon2, double *lat2)
 Adjusts longitude and latitude to ensure they fall within valid bounds. More...
 
void intpol_check_cartesian (const double *lons, const int nlon, const double *lats, const int nlat, const double lon, const double lat, double *lon2, double *lat2)
 Clamps UTM coordinates to the valid bounds. More...
 
void intpol_met_4d_zeta (const met_t *met0, float heights0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float heights1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double height, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological variables to a given position and time. More...
 
void intpol_met_space_3d (const met_t *met, float array[EX][EY][EP], const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological variables in 3D space. More...
 
void intpol_met_space_2d (const met_t *met, float array[EX][EY], const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological variables in 2D space. More...
 
void intpol_met_time_3d (const met_t *met0, float array0[EX][EY][EP], const met_t *met1, float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological data in 3D space and time. More...
 
void intpol_met_time_2d (const met_t *met0, float array0[EX][EY], const met_t *met1, float array1[EX][EY], const double ts, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological data in 2D space and time. More...
 
void intpol_tropo_3d (const double time0, float array0[EX][EY], const double time1, float array1[EX][EY], const double lons[EX], const double lats[EY], const int nlon, const int nlat, const double time, const double lon, const double lat, const int method, double *var, double *sigma)
 Interpolates tropopause data in 3D (latitude, longitude, and time). More...
 
void jsec2time (const double jsec, int *year, int *mon, int *day, int *hour, int *min, int *sec, double *remain)
 Converts Julian seconds to calendar date and time components. More...
 
double kernel_weight (const double kz[EP], const double kw[EP], const int nk, const double p)
 Calculates the kernel weight based on altitude and given kernel data. More...
 
double lapse_rate (const double t, const double h2o)
 Calculates the moist adiabatic lapse rate in Kelvin per kilometer. More...
 
void level_definitions (ctl_t *ctl)
 Defines pressure levels for meteorological data. More...
 
int locate_irr (const double *xx, const int n, const double x)
 Locate the index of the interval containing a given value in a sorted array. More...
 
int locate_irr_float (const float *xx, const int n, const double x, const int ig)
 Locate the index of the interval containing a given value in an irregularly spaced array. More...
 
int locate_reg (const double *xx, const int n, const double x)
 Locate the index of the interval containing a given value in a regular grid. More...
 
void locate_vert (float profiles[EX][EY][EP], const int np, const int lon_ap_ind, const int lat_ap_ind, const double height_ap, int *ind)
 Locate the four vertical indizes of a box for a given height value. More...
 
void module_advect (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Advances particle positions using different advection schemes. More...
 
void module_advect_init (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Initializes the advection module by setting up pressure fields. More...
 
void module_bound_cond (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Apply boundary conditions to particles based on meteorological and climatological data. More...
 
void module_chem_grid (const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double tt)
 Computes gridded chemical tracer concentrations (volume mixing ratio) from individual air parcel mass data and assigns them back to the parcels. More...
 
void module_chem_init (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Initializes the chemistry modules by setting atmospheric composition. More...
 
void module_convection (const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Performs convective mixing of atmospheric particles. More...
 
void module_decay (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, atm_t *atm)
 Simulate exponential decay processes for atmospheric particles. More...
 
void module_diff_meso (const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Simulate mesoscale diffusion for atmospheric particles. More...
 
void module_diff_pbl (const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Computes particle diffusion within the planetary boundary layer (PBL). More...
 
void module_diff_turb (const ctl_t *ctl, cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Applies turbulent diffusion processes to atmospheric particles. More...
 
void module_dry_depo (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Simulate dry deposition of atmospheric particles. More...
 
void module_h2o2_chem (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Perform chemical reactions involving H2O2 within cloud particles. More...
 
void module_isosurf_init (const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Initialize the isosurface module based on atmospheric data. More...
 
void module_isosurf (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Apply the isosurface module to adjust atmospheric properties. More...
 
void module_meteo (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Update atmospheric properties using meteorological data. More...
 
void module_mixing (const ctl_t *ctl, const clim_t *clim, atm_t *atm, const double t)
 Update atmospheric properties through interparcel mixing. More...
 
void module_mixing_help (const ctl_t *ctl, const clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, const int qnt_idx, const int use_ensemble)
 Perform subgrid-scale interparcel mixing of a given quantity. More...
 
void module_oh_chem (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Perform hydroxyl chemistry calculations for atmospheric particles. More...
 
void module_position (const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Update the positions and pressure levels of atmospheric particles. More...
 
void module_radio_decay (const ctl_t *ctl, const cache_t *cache, atm_t *atm)
 Apply radioactive decay to atmospheric tracer species. More...
 
void module_rng_init (const int ntask)
 Initialize random number generators for parallel tasks. More...
 
void module_rng (const ctl_t *ctl, double *rs, const size_t n, const int method)
 Generate random numbers using various methods and distributions. More...
 
void module_sedi (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Simulate sedimentation of particles in the atmosphere. More...
 
void module_sort (const ctl_t *ctl, const met_t *met0, atm_t *atm)
 Sort particles according to box index. More...
 
void module_sort_help (double *a, const int *p, const int np)
 Reorder an array based on a given permutation. More...
 
void module_timesteps (const ctl_t *ctl, cache_t *cache, met_t *met0, atm_t *atm, const double t)
 Calculate time steps for air parcels based on specified conditions. More...
 
void module_timesteps_init (ctl_t *ctl, const atm_t *atm)
 Initialize start time and time interval for time-stepping. More...
 
void module_tracer_chem (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Simulate chemical reactions involving long-lived atmospheric tracers. More...
 
void module_wet_depo (const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
 Perform wet deposition calculations for air parcels. More...
 
void mptrac_alloc (ctl_t **ctl, cache_t **cache, clim_t **clim, met_t **met0, met_t **met1, atm_t **atm, dd_t **dd)
 Allocates and initializes memory resources for MPTRAC. More...
 
void mptrac_free (ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, dd_t *dd)
 Frees memory resources allocated for MPTRAC. More...
 
void mptrac_get_met (ctl_t *ctl, clim_t *clim, const double t, met_t **met0, met_t **met1, dd_t *dd)
 Retrieves meteorological data for the specified time. More...
 
void mptrac_init (ctl_t *ctl, cache_t *cache, clim_t *clim, atm_t *atm, const int ntask)
 Initializes the MPTRAC model and its associated components. More...
 
int mptrac_read_atm (const char *filename, const ctl_t *ctl, atm_t *atm)
 Reads air parcel data from a specified file into the given atmospheric structure. More...
 
void mptrac_read_clim (const ctl_t *ctl, clim_t *clim)
 Reads various climatological data and populates the given climatology structure. More...
 
void mptrac_read_ctl (const char *filename, int argc, char *argv[], ctl_t *ctl)
 Reads control parameters from a configuration file and populates the given structure. More...
 
int mptrac_read_met (const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met, dd_t *dd)
 Reads meteorological data from a file, supporting multiple formats and MPI broadcasting. More...
 
void mptrac_run_timestep (ctl_t *ctl, cache_t *cache, clim_t *clim, met_t **met0, met_t **met1, atm_t *atm, double t, dd_t *dd)
 Executes a single timestep of the MPTRAC model simulation. More...
 
void mptrac_update_device (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
 Updates device memory for specified data structures. More...
 
void mptrac_update_host (const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
 Updates host memory for specified data structures. More...
 
void mptrac_write_atm (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes air parcel data to a file in various formats. More...
 
void mptrac_write_met (const char *filename, const ctl_t *ctl, met_t *met)
 Writes meteorological data to a file, supporting multiple formats and compression options. More...
 
void mptrac_write_output (const char *dirname, const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double t)
 Writes various types of output data to files in a specified directory. More...
 
double nat_temperature (const double p, const double h2o, const double hno3)
 Calculates the nitric acid trihydrate (NAT) temperature. More...
 
double pbl_weight (const ctl_t *ctl, const atm_t *atm, const int ip, const double pbl, const double ps)
 Computes a weighting factor based on planetary boundary layer pressure. More...
 
int read_atm_asc (const char *filename, const ctl_t *ctl, atm_t *atm)
 Reads air parcel data from an ASCII file and populates the given atmospheric structure. More...
 
int read_atm_bin (const char *filename, const ctl_t *ctl, atm_t *atm)
 Reads air parcel data from a binary file and populates the given atmospheric structure. More...
 
int read_atm_clams (const char *filename, const ctl_t *ctl, atm_t *atm)
 Reads atmospheric data from a CLAMS NetCDF file. More...
 
int read_atm_nc (const char *filename, const ctl_t *ctl, atm_t *atm)
 Reads air parcel data from a generic netCDF file and populates the given atmospheric structure. More...
 
void read_clim_photo (const char *filename, clim_photo_t *photo)
 Reads photolysis rates from a NetCDF file and populates the given photolysis structure. More...
 
void read_clim_photo_help (const int ncid, const char *varname, const clim_photo_t *photo, double var[CP][CSZA][CO3])
 Reads a 3D climatological photochemistry variable from a NetCDF file. More...
 
int read_clim_ts (const char *filename, clim_ts_t *ts)
 Reads a climatological time series from a file and populates the given time series structure. More...
 
void read_clim_zm (const char *filename, const char *varname, clim_zm_t *zm)
 Reads zonally averaged climatological data from a netCDF file and populates the given structure. More...
 
void read_kernel (const char *filename, double kz[EP], double kw[EP], int *nk)
 Reads kernel function data from a file and populates the provided arrays. More...
 
int read_met_bin (const char *filename, const ctl_t *ctl, met_t *met)
 Reads meteorological data from a binary file. More...
 
void read_met_bin_2d (FILE *in, const met_t *met, float var[EX][EY], const char *varname)
 Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array. More...
 
void read_met_bin_3d (FILE *in, const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname, const float bound_min, const float bound_max)
 Reads 3D meteorological data from a binary file, potentially using different compression methods. More...
 
void read_met_cape (const ctl_t *ctl, const clim_t *clim, met_t *met)
 Calculates Convective Available Potential Energy (CAPE) for each grid point. More...
 
void read_met_cloud (met_t *met)
 Calculates cloud-related variables for each grid point. More...
 
void read_met_detrend (const ctl_t *ctl, met_t *met)
 Detrends meteorological data. More...
 
void read_met_extrapolate (met_t *met)
 Extrapolates meteorological data. More...
 
void read_met_geopot (const ctl_t *ctl, met_t *met)
 Calculates geopotential heights from meteorological data. More...
 
void read_met_nc_grid (const char *filename, const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
 Reads meteorological grid data from NetCDF files with domain decomposition. More...
 
void read_met_nc_surface (const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
 Reads and processes surface meteorological data from NetCDF files with domain decomposition. More...
 
void read_met_nc_levels (const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
 Reads and processes meteorological level data from NetCDF files with domain decomposition. More...
 
int read_met_nc_2d (const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const char *varname5, const char *varname6, const ctl_t *ctl, const met_t *met, dd_t *dd, float dest[EX][EY], const float scl, const int init)
 Reads a 2-dimensional meteorological variable from a NetCDF file. More...
 
int read_met_nc_3d (const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const ctl_t *ctl, const met_t *met, dd_t *dd, float dest[EX][EY][EP], const float scl)
 Reads a 3-dimensional meteorological variable from a NetCDF file. More...
 
void read_met_ml2pl (const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname)
 Interpolates meteorological data to specified pressure levels. More...
 
void read_met_monotonize (const ctl_t *ctl, met_t *met)
 Makes zeta and pressure profiles monotone. More...
 
int read_met_nc (const char *filename, const ctl_t *ctl, met_t *met, dd_t *dd)
 Reads meteorological data from a NetCDF file and processes it. More...
 
void dd_read_met_nc_grid (dd_t *dd, const ctl_t *ctl, met_t *met, const int ncid)
 Read meteorological grid information and construct the domain-decomposed grid with halo regions. More...
 
void read_met_pbl (const ctl_t *ctl, met_t *met)
 Computes the planetary boundary layer (PBL) pressure based on meteorological data. More...
 
void read_met_periodic (met_t *met)
 Applies periodic boundary conditions to meteorological data along longitudinal axis. More...
 
void read_met_polar_winds (met_t *met)
 Applies a fix for polar winds in meteorological data. More...
 
void read_met_pv (met_t *met)
 Calculates potential vorticity (PV) from meteorological data. More...
 
void read_met_ozone (met_t *met)
 Calculates the total column ozone from meteorological ozone data. More...
 
void read_met_sample (const ctl_t *ctl, met_t *met)
 Downsamples meteorological data based on specified parameters. More...
 
void read_met_tropo (const ctl_t *ctl, const clim_t *clim, met_t *met)
 Calculates the tropopause and related meteorological variables based on various methods and stores the results in the meteorological data structure. More...
 
void read_obs (const char *filename, const ctl_t *ctl, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
 Reads observation data from a file and stores it in arrays. More...
 
void read_obs_asc (const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
 Reads observation data from an ASCII file. More...
 
void read_obs_nc (const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
 Reads observation data from a NetCDF file. More...
 
double scan_ctl (const char *filename, int argc, char *argv[], const char *varname, const int arridx, const char *defvalue, char *value)
 Scans a control file or command-line arguments for a specified variable. More...
 
double sedi (const double p, const double T, const double rp, const double rhop)
 Calculates the sedimentation velocity of a particle in air. More...
 
void spline (const double *x, const double *y, const int n, const double *x2, double *y2, const int n2, const int method)
 Performs spline interpolation or linear interpolation. More...
 
float stddev (const float *data, const int n)
 Calculates the standard deviation of a set of data. More...
 
void time2jsec (const int year, const int mon, const int day, const int hour, const int min, const int sec, const double remain, double *jsec)
 Converts time components to seconds since January 1, 2000, 12:00:00 UTC. More...
 
void timer (const char *name, const char *group, const int output)
 Measures and reports elapsed time for named and grouped timers. More...
 
double time_from_filename (const char *filename, const int offset, const int with_seconds)
 Extracts and converts a timestamp from a filename to Julian seconds. More...
 
double tropo_weight (const ctl_t *ctl, const clim_t *clim, const atm_t *atm, const int ip)
 Computes a weighting factor based on tropopause pressure. More...
 
void write_atm_asc (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes air parcel data to an ASCII file or gnuplot. More...
 
void write_atm_bin (const char *filename, const ctl_t *ctl, const atm_t *atm)
 Writes air parcel data to a binary file. More...
 
void write_atm_clams (const char *filename, const ctl_t *ctl, const atm_t *atm)
 Writes air parcel data to a NetCDF file in the CLaMS format. More...
 
void write_atm_clams_traj (const char *dirname, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes CLaMS trajectory data to a NetCDF file. More...
 
void write_atm_nc (const char *filename, const ctl_t *ctl, const atm_t *atm)
 Writes air parcel data to a NetCDF file. More...
 
void write_csi (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes Critical Success Index (CSI) data to a file. More...
 
void write_ens (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes ensemble data to a file. More...
 
void write_grid (const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
 Writes grid data to a file in ASCII or netCDF format. More...
 
void write_grid_asc (const char *filename, const ctl_t *ctl, const double *cd, double *mean[NQ], double *sigma[NQ], const double *vmr_impl, const double t, const double *z, const double *lon, const double *lat, const double *area, const double dz, const int *np)
 Writes grid data to an ASCII file. More...
 
void write_grid_nc (const char *filename, const ctl_t *ctl, const double *cd, double *mean[NQ], double *sigma[NQ], const double *vmr_impl, const double t, const double *z, const double *lon, const double *lat, const double *area, const double dz, const int *np)
 Writes grid data to a NetCDF file. More...
 
void write_met_bin (const char *filename, const ctl_t *ctl, met_t *met)
 Writes meteorological data in binary format to a specified file. More...
 
void write_met_bin_2d (FILE *out, met_t *met, float var[EX][EY], const char *varname)
 Writes a 2-dimensional meteorological variable to a binary file. More...
 
void write_met_bin_3d (FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int metvar, FILE *level_log)
 Writes a 3-dimensional meteorological variable to a binary file. More...
 
void write_met_nc (const char *filename, const ctl_t *ctl, met_t *met)
 Writes meteorological data to a NetCDF file. More...
 
void write_met_nc_2d (const int ncid, const char *varname, met_t *met, float var[EX][EY], const float scl)
 Writes a 2D meteorological variable to a NetCDF file. More...
 
void write_met_nc_3d (const int ncid, const char *varname, met_t *met, float var[EX][EY][EP], const float scl)
 Writes a 3D meteorological variable to a NetCDF file. More...
 
void write_prof (const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
 Writes profile data to a specified file. More...
 
void write_sample (const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
 Writes sample data to a specified file. More...
 
void write_station (const char *filename, const ctl_t *ctl, atm_t *atm, const double t)
 Writes station data to a specified file. More...
 
void write_vtk (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes VTK (Visualization Toolkit) data to a specified file. More...
 

Detailed Description

MPTRAC library definitions.

Definition in file mptrac.c.

Function Documentation

◆ cart2geo()

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

State variables of cuRAND random number generator.

Converts Cartesian coordinates to geographic coordinates.

Definition at line 74 of file mptrac.c.

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

◆ clim_oh()

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

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

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

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

Definition at line 89 of file mptrac.c.

95 {
96
97 /* Set SZA threshold... */
98 const double sza_thresh = DEG2RAD(85.), csza_thresh = cos(sza_thresh);
99
100 /* Set reference coordinates... */
101 const double lat_ref =
102 ctl->met_coord_type == 0 ? lat : ctl->met_utm_ref_lat;
103 double lon_ref = ctl->met_coord_type == 0 ? lon : ctl->met_utm_ref_lon;
104 while (lon_ref < -180.0)
105 lon_ref += 360.0;
106 while (lon_ref >= 180.0)
107 lon_ref -= 360.0;
108
109 /* Get OH data from climatology... */
110 const double oh = clim_zm(&clim->oh, t, lat_ref, p);
111
112 /* Check beta... */
113 if (ctl->oh_chem_beta <= 0)
114 return oh;
115
116 /* Apply diurnal correction... */
117 const double csza = cos_sza(t, lon_ref, lat_ref);
118 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
119 return oh * exp(-ctl->oh_chem_beta / denom);
120}
double cos_sza(const double sec, const double lon, const double lat)
Calculates the cosine of the solar zenith angle.
Definition: mptrac.c:1857
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:414
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:647
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3560
double met_utm_ref_lon
Reference longitude [deg] for UTM grid.
Definition: mptrac.h:2643
double met_utm_ref_lat
Reference latitude [deg] for UTM grid.
Definition: mptrac.h:2640
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:3024
int met_coord_type
Type of coordinates for meteo data (-1=detect, 0=lat/lon [deg], 1=UTM [m]).
Definition: mptrac.h:2637
Here is the call graph for this function:

◆ clim_oh_diurnal_correction()

void clim_oh_diurnal_correction ( const ctl_t ctl,
clim_t clim 
)

Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data.

This function iterates over the climatology data points for OH concentration and integrates the day/night correction factor over longitude. The correction factor is based on the solar zenith angle, and it adjusts the OH data to account for diurnal variations. The corrected OH data is scaled accordingly.

Parameters
ctlPointer to the control structure containing configuration parameters, including the correction factor (oh_chem_beta).
climPointer to the climatology structure containing OH data that will be corrected.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 124 of file mptrac.c.

126 {
127
128 /* Set SZA threshold... */
129 const double sza_thresh = DEG2RAD(85.), csza_thresh = cos(sza_thresh);
130
131 /* Loop over climatology data points... */
132 for (int it = 0; it < clim->oh.ntime; it++)
133 for (int iz = 0; iz < clim->oh.np; iz++)
134 for (int iy = 0; iy < clim->oh.nlat; iy++) {
135
136 /* Init... */
137 int n = 0;
138 double sum = 0;
139
140 /* Integrate day/night correction factor over longitude... */
141 for (double lon = -180; lon < 180; lon += 1.0) {
142 const double csza =
143 cos_sza(clim->oh.time[it], lon, clim->oh.lat[iy]);
144 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
145 sum += exp(-ctl->oh_chem_beta / denom);
146 n++;
147 }
148
149 /* Apply scaling factor to OH data... */
150 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
151 }
152}
double time[CT]
Time [s].
Definition: mptrac.h:3516
int np
Number of pressure levels.
Definition: mptrac.h:3513
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3525
int ntime
Number of timesteps.
Definition: mptrac.h:3507
int nlat
Number of latitudes.
Definition: mptrac.h:3510
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3519
Here is the call graph for this function:

◆ clim_photo()

double clim_photo ( const double  rate[CP][CSZA][CO3],
const clim_photo_t photo,
const double  p,
const double  sza,
const double  o3c 
)

Calculates the photolysis rate for a given set of atmospheric conditions.

This function computes the photolysis rate based on provided climatology data and input parameters such as pressure, solar zenith angle (SZA), and ozone column. It ensures that the input parameters are within the valid range of the climatology data and interpolates the photolysis rate accordingly.

Parameters
rate3D array containing the photolysis rates for different combinations of pressure, SZA, and ozone column.
photoPointer to the climatology data structure containing arrays of valid pressure levels, SZAs, and ozone columns.
pPressure at which the photolysis rate is to be calculated.
szaSolar zenith angle at which the photolysis rate is to be calculated.
o3cOzone column at which the photolysis rate is to be calculated.
Returns
The interpolated photolysis rate for the specified conditions. If the calculated rate is negative, it returns 0.0.

This function performs the following steps:

  1. Checks and adjusts the input parameters (pressure, SZA, and ozone column) to ensure they are within the valid range.
  2. Determines the appropriate indices in the climatology data for interpolation.
  3. Performs trilinear interpolation to calculate the photolysis rate based on the input parameters.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 156 of file mptrac.c.

161 {
162
163 /* Check pressure range... */
164 double p_help = p;
165 if (p < photo->p[photo->np - 1])
166 p_help = photo->p[photo->np - 1];
167 else if (p > photo->p[0])
168 p_help = photo->p[0];
169
170 /* Check sza range... */
171 double sza_help = sza;
172 if (sza < photo->sza[0])
173 sza_help = photo->sza[0];
174 else if (sza > photo->sza[photo->nsza - 1])
175 sza_help = photo->sza[photo->nsza - 1];
176
177 /* Check ozone column range... */
178 double o3c_help = o3c;
179 if (o3c < photo->o3c[0])
180 o3c_help = photo->o3c[0];
181 else if (o3c > photo->o3c[photo->no3c - 1])
182 o3c_help = photo->o3c[photo->no3c - 1];
183
184 /* Get indices... */
185 const int ip = locate_irr(photo->p, photo->np, p_help);
186 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
187 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
188
189 /* Interpolate photolysis rate... */
190 const double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
191 photo->p[ip + 1], rate[ip + 1][isza][io3c],
192 p_help);
193 const double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
194 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1],
195 p_help);
196 const double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
197 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c],
198 p_help);
199 const double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
200 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
201 p_help);
202 const double aux0 =
203 LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
204 const double aux1 =
205 LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
206 const double aux =
207 LIN(photo->sza[isza], aux0, photo->sza[isza + 1], aux1, sza_help);
208 return MAX(aux, 0.0);
209}
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:3559
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:3495
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1141
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1168
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3434
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3443
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3440
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3446
int np
Number of pressure levels.
Definition: mptrac.h:3431
int no3c
Number of total ozone columns.
Definition: mptrac.h:3437
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 213 of file mptrac.c.

216 {
217
218 /* Get seconds since begin of year... */
219 double sec = FMOD(t, 365.25 * 86400.);
220 while (sec < 0)
221 sec += 365.25 * 86400.;
222
223 /* Get indices... */
224 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
225 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
226
227 /* Interpolate tropopause pressure... */
228 const double p0 = LIN(clim->tropo_lat[ilat],
229 clim->tropo[isec][ilat],
230 clim->tropo_lat[ilat + 1],
231 clim->tropo[isec][ilat + 1], lat);
232 const double p1 = LIN(clim->tropo_lat[ilat],
233 clim->tropo[isec + 1][ilat],
234 clim->tropo_lat[ilat + 1],
235 clim->tropo[isec + 1][ilat + 1], lat);
236 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
237}
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:911
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3539
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3548
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3542
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3551
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3545
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 241 of file mptrac.c.

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

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

398 {
399
400 /* Interpolate... */
401 if (t <= ts->time[0])
402 return ts->vmr[0];
403 else if (t >= ts->time[ts->ntime - 1])
404 return ts->vmr[ts->ntime - 1];
405 else {
406 const int idx = locate_irr(ts->time, ts->ntime, t);
407 return LIN(ts->time[idx], ts->vmr[idx],
408 ts->time[idx + 1], ts->vmr[idx + 1], t);
409 }
410}
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3493
double time[CTS]
Time [s].
Definition: mptrac.h:3490
int ntime
Number of timesteps.
Definition: mptrac.h:3487
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 414 of file mptrac.c.

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

◆ compress_log_level()

void compress_log_level ( FILE *  out,
const char *  codec,
const char *  varname,
const size_t  lev,
const double  plev,
const double  ratio,
const double  bpv,
const double  t_comp,
const double  t_decomp,
const size_t  n,
const size_t  nbytes,
const float *  org,
const float *  cmp 
)

Write one row of per-level compression diagnostics.

This helper computes the error statistics for one level (from org and cmp) and writes one ASCII table row to out. If rho is NAN, the correlation coefficient is derived from org and cmp using GSL.

Parameters
[in,out]outOutput stream.
[in]codecCompression codec name.
[in]varnameVariable name.
[in]levLevel index.
[in]plevPressure level in hPa.
[in]ratioCompression ratio.
[in]bpvBits per value.
[in]t_compCompression time in seconds.
[in]t_decompDecompression time in seconds.
[in]nNumber of data values in the level slice.
[in]nbytesByte count used for throughput reporting.
[in]orgOriginal level data.
[in]cmpReconstructed level data.
Author
Lars Hoffmann

Definition at line 666 of file mptrac.c.

679 {
680
681 static FILE *last_out = NULL;
682 static char last_var[LEN] = "";
683
684 /* Calculate error statistics... */
685 double mean_err = 0.0, stddev_err = 0.0;
686 double nrmse = NAN, mean_orig = 0.0, orig_range = 0.0, rho = NAN;
687
688 double sum_err = 0.0, sumsq_err = 0.0;
689 double sum_orig = 0.0, sum_cmp = 0.0;
690 double sumsq_orig = 0.0, sumsq_cmp = 0.0, sum_org_cmp = 0.0;
691
692 double min_orig = 0.0, max_orig = 0.0;
693 double min_err = 0.0, max_err = 0.0;
694
695 /* Accumulate error, signal and cross-product sums in one pass... */
696 for (size_t i = 0; i < n; i++) {
697 const double o = (double) org[i];
698 const double c = (double) cmp[i];
699 const double e = c - o;
700
701 sum_err += e;
702 sumsq_err += e * e;
703 sum_orig += o;
704 sum_cmp += c;
705
706 sumsq_orig += o * o;
707 sumsq_cmp += c * c;
708 sum_org_cmp += o * c;
709
710 if (e < min_err || i == 0)
711 min_err = e;
712 if (e > max_err || i == 0)
713 max_err = e;
714
715 if (o < min_orig || i == 0)
716 min_orig = o;
717 if (o > max_orig || i == 0)
718 max_orig = o;
719 }
720
721 /* Derive the basic error and signal summary statistics... */
722 mean_err = sum_err / (double) n;
723 mean_orig = sum_orig / (double) n;
724 orig_range = max_orig - min_orig;
725
726 /* Convert the accumulated error sums into a standard deviation... */
727 const double var_err =
728 (sumsq_err - (sum_err * sum_err) / (double) n) / (double) n;
729 stddev_err = sqrt(var_err > 0.0 ? var_err : 0.0);
730
731 /* Normalize RMSE by the original data range if available... */
732 nrmse = (orig_range > 0.0)
733 ? sqrt(sumsq_err / (double) n) / orig_range : NAN;
734
735 /* Compute the Pearson correlation from the accumulated moments... */
736 const double nn = (double) n;
737 const double cov = sum_org_cmp - sum_orig * sum_cmp / nn;
738 const double var_orig = sumsq_orig - sum_orig * sum_orig / nn;
739 const double var_cmp = sumsq_cmp - sum_cmp * sum_cmp / nn;
740 const double denom = sqrt(var_orig * var_cmp);
741 rho = denom > 0.0 ? cov / denom : NAN;
742
743 /* Reset the variable separator state when the target file changes... */
744 if (out != last_out) {
745 last_out = out;
746 last_var[0] = '\0';
747 }
748
749 /* Separate diagnostic blocks when switching to a new variable... */
750 if (last_var[0] != '\0' && strcmp(last_var, varname) != 0)
751 fprintf(out, "\n");
752 snprintf(last_var, LEN, "%s", varname);
753
754 /* Logging... */
755 fprintf(out,
756 "%s %s %lu %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n",
757 codec, varname, (unsigned long) lev, plev, ratio, bpv, rho,
758 mean_err, stddev_err, min_err, max_err, mean_orig, orig_range,
759 nrmse, t_comp, COMPRESS_SPEED(nbytes, t_comp), t_decomp,
760 COMPRESS_SPEED(nbytes, t_decomp));
761}
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:349
#define COMPRESS_SPEED(nbytes, dt)
Calculate compression throughput in MiB/s.
Definition: mptrac.h:561

◆ compress_log_levels_3d()

void compress_log_levels_3d ( FILE *  out,
const char *  codec,
const char *  varname,
const met_t met,
const float *  org_all,
const float *  cmp_all,
const size_t  nxy,
const size_t  nz,
const double  ratio,
const double  bpv,
const double  t_comp,
const double  t_decomp,
const size_t  nbytes 
)

Write per-level compression diagnostics for a full 3-D field.

This helper extracts each vertical level from the original and reconstructed 3-D fields and forwards the diagnostics to compress_log_level().

Parameters
[in,out]outOutput stream, or NULL to disable logging.
[in]codecCompression codec name.
[in]varnameVariable name.
[in]metMeteorological meta-data with pressure levels.
[in]org_allOriginal 3-D field in horizontal-major order.
[in]cmp_allReconstructed 3-D field in horizontal-major order.
[in]nxyNumber of horizontal points per level.
[in]nzNumber of vertical levels.
[in]ratioCompression ratio.
[in]bpvBits per value.
[in]t_compCompression time in seconds.
[in]t_decompDecompression time in seconds.
[in]nbytesByte count used for throughput reporting.
Author
Lars Hoffmann

Definition at line 765 of file mptrac.c.

778 {
779
780 if (!out)
781 return;
782
783 /* Allocate temporary buffers for one level... */
784 float *tmp_org, *tmp_cmp;
785 ALLOC(tmp_org, float,
786 nxy);
787 ALLOC(tmp_cmp, float,
788 nxy);
789
790 for (size_t lev = 0; lev < nz; lev++) {
791
792 /* Extract current level... */
793#pragma omp parallel for default(shared)
794 for (size_t ixy = 0; ixy < nxy; ixy++) {
795 tmp_org[ixy] = org_all[ixy * nz + lev];
796 tmp_cmp[ixy] = cmp_all[ixy * nz + lev];
797 }
798
799 /* Write diagnostics for the extracted level... */
800 compress_log_level(out, codec, varname, lev, met->p[lev], ratio, bpv,
801 t_comp, t_decomp, nxy, nbytes, tmp_org, tmp_cmp);
802 }
803
804 /* Free... */
805 free(tmp_org);
806 free(tmp_cmp);
807}
void compress_log_level(FILE *out, const char *codec, const char *varname, const size_t lev, const double plev, const double ratio, const double bpv, const double t_comp, const double t_decomp, const size_t n, const size_t nbytes, const float *org, const float *cmp)
Write one row of per-level compression diagnostics.
Definition: mptrac.c:666
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:457
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3622
Here is the call graph for this function:

◆ compress_scale_to_unit()

void compress_scale_to_unit ( float *  array,
const size_t  nxy,
const size_t  nz,
double *  off,
double *  scl 
)

Scales each vertical level of a 3-D field independently to the interval [0,1].

The routine computes per-level offsets and scales from the minimum and maximum values of each vertical slice and transforms the field in place. Constant or nearly constant levels are mapped to zero and can be reconstructed exactly with the stored offsets.

Parameters
[in,out]arrayField values stored in horizontal-major order.
[in]nxyNumber of horizontal points per level.
[in]nzNumber of vertical levels.
[out]offPer-level offsets (minimum values).
[out]sclPer-level scales (ranges).
Author
Lars Hoffmann

Definition at line 811 of file mptrac.c.

816 {
817
818 /* Initialize per-level minima and maxima from the first sample... */
819 for (size_t iz = 0; iz < nz; iz++) {
820 off[iz] = array[iz];
821 scl[iz] = array[iz];
822 }
823
824 /* Scan the remaining samples to get per-level minima and maxima... */
825 for (size_t ixy = 1; ixy < nxy; ixy++)
826 for (size_t iz = 0; iz < nz; iz++) {
827 const double value = array[ixy * nz + iz];
828 if (value < off[iz])
829 off[iz] = value;
830 if (value > scl[iz])
831 scl[iz] = value;
832 }
833
834 /* Convert maxima into ranges and suppress numerically flat levels... */
835 for (size_t iz = 0; iz < nz; iz++) {
836 const double range = scl[iz] - off[iz];
837 const double ref = fmax(1.0, fmax(fabs(off[iz]), fabs(scl[iz])));
838 scl[iz] = !(range > 1e-12 * ref) ? 0.0 : range;
839 }
840
841 /* Scale each level independently to the unit interval... */
842#pragma omp parallel for default(shared)
843 for (size_t ixy = 0; ixy < nxy; ixy++)
844 for (size_t iz = 0; iz < nz; iz++)
845 if (scl[iz] > 0.0)
846 array[ixy * nz + iz] =
847 (float) ((array[ixy * nz + iz] - off[iz]) / scl[iz]);
848 else
849 array[ixy * nz + iz] = 0.0f;
850}

◆ compress_unscale_from_unit()

void compress_unscale_from_unit ( float *  array,
const size_t  nxy,
const size_t  nz,
const double *  off,
const double *  scl 
)

Restores a levelwise [0,1]-scaled 3-D field to physical units.

This routine applies the inverse transformation of compress_scale_to_unit() using the supplied per-level offsets and scales. Constant levels are restored directly from their offsets.

Parameters
[in,out]arrayField values stored in horizontal-major order.
[in]nxyNumber of horizontal points per level.
[in]nzNumber of vertical levels.
[in]offPer-level offsets (minimum values).
[in]sclPer-level scales (ranges).
Author
Lars Hoffmann

Definition at line 854 of file mptrac.c.

859 {
860
861 /* Restore each level from unit space back to its original range... */
862#pragma omp parallel for default(shared)
863 for (size_t ixy = 0; ixy < nxy; ixy++)
864 for (size_t iz = 0; iz < nz; iz++)
865 if (scl[iz] > 0.0)
866 array[ixy * nz + iz] =
867 (float) (array[ixy * nz + iz] * scl[iz] + off[iz]);
868 else
869 array[ixy * nz + iz] = (float) off[iz];
870}

◆ compress_read_lossy_scale()

int compress_read_lossy_scale ( FILE *  in,
const size_t  nz,
double **  off,
double **  scl 
)

Read optional lossyscaling metadata for a 3-D field.

This helper reads the stored MET_LOSSY_SCALE flag and, if enabled, allocates and fills the per-level offset and scale arrays used by compress_unscale_from_unit(). The caller owns the returned arrays and must free them.

Parameters
[in,out]inInput stream.
[in]nzNumber of vertical levels.
[out]offReturned per-level offsets, or NULL if disabled.
[out]sclReturned per-level scales, or NULL if disabled.
Returns
Stored lossyscaling flag (0 or 1).
Author
Lars Hoffmann

Definition at line 874 of file mptrac.c.

878 {
879
880 int enabled;
881 *off = NULL;
882 *scl = NULL;
883
884 /* Read input... */
885 FREAD(&enabled, int,
886 1,
887 in);
888 if (enabled < 0 || enabled > 1)
889 ERRMSG("Invalid stored MET_LOSSY_SCALE flag!");
890
891 if (enabled > 0) {
892 ALLOC(*off, double,
893 nz);
894 ALLOC(*scl, double,
895 nz);
896 FREAD(*off, double,
897 nz,
898 in);
899 FREAD(*scl, double,
900 nz,
901 in);
902 }
903
904 return enabled;
905}
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2196
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:929

◆ compress_write_lossy_scale()

void compress_write_lossy_scale ( FILE *  out,
const int  enabled,
float *  array,
const size_t  nxy,
const size_t  nz,
double **  off,
double **  scl 
)

Write optional lossyscaling metadata for a 3-D field.

This helper writes the MET_LOSSY_SCALE flag and, if enabled, allocates the per-level offset and scale arrays, scales the field in place to [0,1], and writes the resulting metadata to out. The caller owns the returned arrays and must free them.

Parameters
[in,out]outOutput stream.
[in]enabledLossyscaling flag (0 or 1).
[in,out]arrayField values stored in horizontal-major order.
[in]nxyNumber of horizontal points per level.
[in]nzNumber of vertical levels.
[out]offReturned per-level offsets, or NULL if disabled.
[out]sclReturned per-level scales, or NULL if disabled.
Author
Lars Hoffmann

Definition at line 909 of file mptrac.c.

916 {
917
918 *off = NULL;
919 *scl = NULL;
920
921 /* Write output... */
922 FWRITE(&enabled, int,
923 1,
924 out);
925 if (enabled <= 0)
926 return;
927
928 /* Derive per-level scaling data... */
929 ALLOC(*off, double,
930 nz);
931 ALLOC(*scl, double,
932 nz);
933
934 compress_scale_to_unit(array, nxy, nz, *off, *scl);
935
936 FWRITE(*off, double,
937 nz,
938 out);
939 FWRITE(*scl, double,
940 nz,
941 out);
942}
void compress_scale_to_unit(float *array, const size_t nxy, const size_t nz, double *off, double *scl)
Scales each vertical level of a 3-D field independently to the interval [0,1].
Definition: mptrac.c:811
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:949
Here is the call graph for this function:

◆ compress_metvar_index()

int compress_metvar_index ( const char *  varname)

Maps a meteorological variable name to its internal MPTRAC variable index.

The returned index can be used to access variable-specific control arrays such as MET_LOSSY_SCALE, MET_ZFP_PREC, and MET_SZ3_PREC.

Parameters
varnameMeteorological variable name as stored in the meteorological file.
Returns
Internal MPTRAC meteorological variable index.
Author
Lars Hoffmann

Definition at line 969 of file mptrac.c.

970 {
971
972 static const char *const names[] = {
973 "Z", "T", "U", "V", "W", "PV", "H2O", "O3",
974 "LWC", "RWC", "IWC", "SWC", "CC"
975 };
976
977 for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); i++)
978 if (strcasecmp(varname, names[i]) == 0)
979 return (int) i;
980
981 ERRMSG("Unknown meteorological variable name!");
982}

◆ compress_pck()

void compress_pck ( const ctl_t ctl,
const met_t met,
const char *  varname,
float *  array,
const int  decompress,
FILE *  level_log,
FILE *  inout 
)

Compresses or decompresses a 3‑D float array using the PCK format.

The routine works on the regular longitude/latitude grid described by the supplied met structure (nx, ny, np and pressure levels). In compress mode the data are scaled to unsigned short values; in decompress mode the values are reconstructed.

Parameters
[in]ctlControl structure with compression parameters.
[in]metMeteorological meta‑data providing grid dimensions and pressure levels.
[in]varnameVariable name for logging and error‑bound selection.
[in,out]arrayFloat array to compress or decompress.
[in]decompressNon‑zero to decompress; zero to compress.
[in,out]level_logOptional per‑level diagnostics stream, or NULL.
[in,out]inoutFile stream for reading/writing the PCK payload.
Author
Lars Hoffmann

Definition at line 986 of file mptrac.c.

993 {
994
995 const size_t nxy = (size_t) met->nx * (size_t) met->ny;
996 const size_t nz = (size_t) met->np;
997 const size_t n = nxy * nz;
998 const size_t nbytes = n * sizeof(float);
999 const size_t pck_bytes = n * sizeof(uint16_t);
1000
1001 double vmin[EP], vmax[EP], off[EP], scl[EP];
1002 uint16_t *sarray;
1003
1004 /* PCK+ZSTD payload = scale + offset + packed 16-bit samples... */
1005 const size_t payload_len = 2 * nz * sizeof(double) + pck_bytes;
1006 size_t stored_len = payload_len;
1007 const char *codec_info = ctl->met_pck_zstd ? "PCK+ZSTD" : "PCK";
1008
1009 /* Allocate packed sample buffer... */
1010 ALLOC(sarray, uint16_t, n);
1011
1012 /* Read compressed stream and decompress array... */
1013 if (decompress) {
1014 double t_zstd = 0.0;
1015
1016 /* Read packed data... */
1017 if (ctl->met_pck_zstd) {
1018#ifdef ZSTD
1019 uint64_t magic, pck_zstd_magic = UINT64_C(0x50434b5a53544431);
1020 unsigned char *compr = NULL, *payload = NULL;
1021
1022 /* Read input... */
1023 FREAD(&magic, uint64_t, 1, inout);
1024 if (magic != pck_zstd_magic)
1025 ERRMSG("PCK+ZSTD magic mismatch! Check MET_PCK_ZSTD and file type.");
1026
1027 /* Read and decompress the outer ZSTD payload... */
1028 FREAD(&stored_len, size_t,
1029 1,
1030 inout);
1031 ALLOC(compr, unsigned char,
1032 stored_len);
1033 FREAD(compr, unsigned char,
1034 stored_len,
1035 inout);
1036 ALLOC(payload, unsigned char,
1037 payload_len);
1038 const double t0_decomp = omp_get_wtime();
1039 const size_t out_len =
1040 ZSTD_decompress(payload, payload_len, compr, stored_len);
1041 t_zstd = omp_get_wtime() - t0_decomp;
1042 if (ZSTD_isError(out_len) || out_len != payload_len)
1043 ERRMSG("PCK ZSTD decompression failed or size mismatch!");
1044
1045 /* Split payload into scale, offset and packed samples... */
1046 memcpy(scl, payload, nz * sizeof(double));
1047 memcpy(off, payload + nz * sizeof(double), nz * sizeof(double));
1048 memcpy(sarray, payload + 2 * nz * sizeof(double), pck_bytes);
1049
1050 /* Free... */
1051 free(payload);
1052 free(compr);
1053#else
1054 ERRMSG("MPTRAC was compiled without ZSTD compression!");
1055#endif
1056 } else {
1057 /* Read input... */
1058 FREAD(&scl, double,
1059 nz,
1060 inout);
1061 FREAD(&off, double,
1062 nz,
1063 inout);
1064 FREAD(sarray, uint16_t, n, inout);
1065 }
1066
1067 /* Measure the scalar unpacking step separately from optional ZSTD... */
1068 const double t0 = omp_get_wtime();
1069
1070 /* Convert packed 16-bit samples back to floating-point values... */
1071#pragma omp parallel for default(shared)
1072 for (size_t ixy = 0; ixy < nxy; ixy++)
1073 for (size_t iz = 0; iz < nz; iz++)
1074 array[ixy * nz + iz]
1075 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1076
1077 /* Add optional ZSTD time to the scalar unpacking time... */
1078 const double t_decomp = t_zstd + omp_get_wtime() - t0;
1079
1080 /* Logging... */
1081 LOG(2, "Read 3-D variable: %s"
1082 " (%s, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1083 varname, codec_info, COMPRESS_RATIO(nbytes, stored_len),
1084 COMPRESS_BPV(n, stored_len), t_decomp, COMPRESS_SPEED(nbytes,
1085 t_decomp));
1086 }
1087
1088 /* Compress array and output compressed stream... */
1089 else {
1090 float *tmp_org, *tmp_pck;
1091 double t_comp_sum = 0, t_decomp_sum = 0, t_zstd = 0, t_zstd_decomp = 0;
1092 double t_comp_level[EP], t_decomp_level[EP];
1093
1094 /* Allocate temporary buffers for one level... */
1095 ALLOC(tmp_org, float,
1096 nxy);
1097 ALLOC(tmp_pck, float,
1098 nxy);
1099
1100 /* Derive per-level minima and maxima for the 16-bit quantization... */
1101 for (size_t iz = 0; iz < nz; iz++) {
1102 vmin[iz] = array[iz];
1103 vmax[iz] = array[iz];
1104 }
1105 for (size_t ixy = 1; ixy < nxy; ixy++)
1106 for (size_t iz = 0; iz < nz; iz++) {
1107 if (array[ixy * nz + iz] < vmin[iz])
1108 vmin[iz] = array[ixy * nz + iz];
1109 if (array[ixy * nz + iz] > vmax[iz])
1110 vmax[iz] = array[ixy * nz + iz];
1111 }
1112
1113 /* Derive per-level offset and scaling factor... */
1114 for (size_t iz = 0; iz < nz; iz++) {
1115 scl[iz] = (vmax[iz] - vmin[iz]) / 65533.;
1116 off[iz] = vmin[iz];
1117 }
1118
1119 /* Quantize each level and time encode/decode diagnostics on the fly... */
1120 for (size_t iz = 0; iz < nz; iz++) {
1121 const double t0 = omp_get_wtime();
1122
1123#pragma omp parallel for default(shared)
1124 for (size_t ixy = 0; ixy < nxy; ixy++)
1125 if (scl[iz] != 0)
1126 sarray[ixy * nz + iz] =
1127 (uint16_t) ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
1128 else
1129 sarray[ixy * nz + iz] = 0;
1130
1131 t_comp_level[iz] = omp_get_wtime() - t0;
1132 t_comp_sum += t_comp_level[iz];
1133
1134 const double t1 = omp_get_wtime();
1135
1136#pragma omp parallel for default(shared)
1137 for (size_t ixy = 0; ixy < nxy; ixy++) {
1138 tmp_org[ixy] = array[ixy * nz + iz];
1139 tmp_pck[ixy] = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1140 }
1141
1142 t_decomp_level[iz] = omp_get_wtime() - t1;
1143 t_decomp_sum += t_decomp_level[iz];
1144 }
1145
1146 /* Write packed data, optionally wrapped in ZSTD... */
1147 if (ctl->met_pck_zstd) {
1148#ifdef ZSTD
1149 uint64_t pck_zstd_magic = UINT64_C(0x50434b5a53544431);
1150 unsigned char *payload = NULL, *payload_chk = NULL;
1151 void *stored_data = NULL;
1152
1153 /* Pack plain PCK data into one ZSTD payload... */
1154 ALLOC(payload, unsigned char,
1155 payload_len);
1156 memcpy(payload, scl, nz * sizeof(double));
1157 memcpy(payload + nz * sizeof(double), off, nz * sizeof(double));
1158 memcpy(payload + 2 * nz * sizeof(double), sarray, pck_bytes);
1159 const size_t dst_cap = ZSTD_compressBound(payload_len);
1160 ALLOC(stored_data, char,
1161 dst_cap);
1162 ZSTD_CCtx *cctx = compress_zstd_create_cctx(ctl->met_zstd_level,
1163 ctl->met_zstd_nworkers);
1164 const double t0_comp = omp_get_wtime();
1165 stored_len =
1166 ZSTD_compress2(cctx, stored_data, dst_cap, payload, payload_len);
1167 t_zstd = omp_get_wtime() - t0_comp;
1168 ZSTD_freeCCtx(cctx);
1169 if (ZSTD_isError(stored_len))
1170 ERRMSG("PCK ZSTD compression failed!");
1171
1172 /* Decompress once for validation and timing... */
1173 ALLOC(payload_chk, unsigned char,
1174 payload_len);
1175 const double t0_decomp2 = omp_get_wtime();
1176 const size_t out_len2 =
1177 ZSTD_decompress(payload_chk, payload_len, stored_data, stored_len);
1178 t_zstd_decomp = omp_get_wtime() - t0_decomp2;
1179 if (ZSTD_isError(out_len2) || out_len2 != payload_len)
1180 ERRMSG("PCK ZSTD decompression failed or size mismatch!");
1181
1182 /* Free... */
1183 free(payload_chk);
1184 free(payload);
1185
1186 /* Write output... */
1187 FWRITE(&pck_zstd_magic, uint64_t, 1, inout);
1188 FWRITE(&stored_len, size_t,
1189 1,
1190 inout);
1191 FWRITE(stored_data, unsigned char,
1192 stored_len,
1193 inout);
1194
1195 /* Free... */
1196 free(stored_data);
1197#else
1198 ERRMSG("MPTRAC was compiled without ZSTD compression!");
1199#endif
1200 } else {
1201
1202 /* Write output... */
1203 FWRITE(&scl, double,
1204 nz,
1205 inout);
1206 FWRITE(&off, double,
1207 nz,
1208 inout);
1209 FWRITE(sarray, uint16_t, n, inout);
1210 }
1211
1212 /* Combine PCK and optional ZSTD timing and size metrics... */
1213 const double ratio_out = COMPRESS_RATIO(nbytes, stored_len);
1214 const double bpv_out = COMPRESS_BPV(n, stored_len);
1215 const double t_comp = t_comp_sum + t_zstd;
1216 const double t_decomp = t_decomp_sum + t_zstd_decomp;
1217
1218 /* Logging... */
1219 LOG(2, "Write 3-D variable: %s"
1220 " (%s, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1221 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1222 varname, codec_info, ratio_out, bpv_out, t_comp,
1223 COMPRESS_SPEED(nbytes, t_comp), t_decomp,
1224 COMPRESS_SPEED(nbytes, t_decomp));
1225
1226 /* Distribute optional ZSTD cost across levels for diagnostics... */
1227 if (level_log) {
1228 const double t_zstd_level = t_zstd / (double) nz;
1229 const double t_zstd_decomp_level = t_zstd_decomp / (double) nz;
1230 const char *codec = ctl->met_pck_zstd ? "PCKZSTD" : "PCK";
1231 for (size_t iz = 0; iz < nz; iz++) {
1232#pragma omp parallel for default(shared)
1233
1234 /* Rebuild one decoded level for diagnostics... */
1235 for (size_t ixy = 0; ixy < nxy; ixy++) {
1236 tmp_org[ixy] = array[ixy * nz + iz];
1237 tmp_pck[ixy] = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1238 }
1239
1240 /* Logging... */
1241 compress_log_level(level_log, codec, varname, iz, met->p[iz],
1242 ratio_out, bpv_out,
1243 t_comp_level[iz] + t_zstd_level,
1244 t_decomp_level[iz] + t_zstd_decomp_level,
1245 nxy, nxy * sizeof(float), tmp_org, tmp_pck);
1246 }
1247 }
1248
1249 /* Free... */
1250 free(tmp_org);
1251 free(tmp_pck);
1252 }
1253
1254 /* Free... */
1255 free(sarray);
1256}
#define COMPRESS_BPV(n, stored_size)
Calculate bits per value from stored size and element count.
Definition: mptrac.h:585
#define COMPRESS_RATIO(raw_size, stored_size)
Calculate the compression ratio from raw and stored byte counts.
Definition: mptrac.h:573
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:334
int met_zstd_nworkers
ZSTD number of worker threads (0=single-threaded, default=4).
Definition: mptrac.h:2672
int met_zstd_level
ZSTD compression level (from -5 to 22, default=-3).
Definition: mptrac.h:2669
int met_pck_zstd
Apply an additional ZSTD compression step to PCK payloads (0=off, 1=on).
Definition: mptrac.h:2678
int nx
Number of longitudes.
Definition: mptrac.h:3604
int ny
Number of latitudes.
Definition: mptrac.h:3607
int np
Number of pressure levels.
Definition: mptrac.h:3610
Here is the call graph for this function:

◆ cos_sza()

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

Calculates the cosine of the solar zenith angle.

This function computes the cosine of the solar zenith angle (SZA), which describes the angle between the local zenith (straight up) and the line connecting the observer to the center of the Sun. The cosine of the SZA is often used directly in radiative transfer and photochemical calculations to avoid unnecessary use of trigonometric inverse functions.

Parameters
secSeconds elapsed since 2000-01-01T12:00Z.
lonObserver's longitude in degrees.
latObserver's latitude in degrees.
Returns
The cosine of the solar zenith angle (dimensionless, range [-1, 1]).

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

Note
The input longitude and latitude must be specified in degrees.
See also
acos() — can be used to convert the returned value to the solar zenith angle in radians if needed.
Author
Lars Hoffmann

Definition at line 1857 of file mptrac.c.

1860 {
1861
1862 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
1863 const double D = sec / 86400 - 0.5;
1864
1865 /* Geocentric apparent ecliptic longitude [rad]... */
1866 const double g = DEG2RAD(357.529 + 0.98560028 * D);
1867 const double q = 280.459 + 0.98564736 * D;
1868 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
1869
1870 /* Mean obliquity of the ecliptic [rad]... */
1871 const double e = DEG2RAD(23.439 - 0.00000036 * D);
1872
1873 /* Declination [rad]... */
1874 const double sindec = sin(e) * sin(L);
1875
1876 /* Right ascension [rad]... */
1877 const double ra = atan2(cos(e) * sin(L), cos(L));
1878
1879 /* Greenwich Mean Sidereal Time [h]... */
1880 const double GMST = 18.697374558 + 24.06570982441908 * D;
1881
1882 /* Local Sidereal Time [h]... */
1883 const double LST = GMST + lon / 15;
1884
1885 /* Hour angle [rad]... */
1886 const double h = LST / 12 * M_PI - ra;
1887
1888 /* Convert latitude... */
1889 const double lat_help = DEG2RAD(lat);
1890
1891 /* Return cosine of solar zenith angle... */
1892 return sin(lat_help) * sindec + cos(lat_help) * sqrt(1 -
1893 SQR(sindec)) * cos(h);
1894}
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1827

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

1902 {
1903
1904 const int
1905 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1906 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1907
1908 /* Get day of year... */
1909 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
1910 *doy = d0l[mon - 1] + day - 1;
1911 else
1912 *doy = d0[mon - 1] + day - 1;
1913}

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

2536 {
2537
2538 const int
2539 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
2540 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
2541
2542 int i;
2543
2544 /* Get month and day... */
2545 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
2546 for (i = 11; i > 0; i--)
2547 if (d0l[i] <= doy)
2548 break;
2549 *mon = i + 1;
2550 *day = doy - d0l[i] + 1;
2551 } else {
2552 for (i = 11; i > 0; i--)
2553 if (d0[i] <= doy)
2554 break;
2555 *mon = i + 1;
2556 *day = doy - d0[i] + 1;
2557 }
2558}

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

2565 {
2566
2567 double data[2 * EX];
2568
2569 /* Check size... */
2570 if (n > EX)
2571 ERRMSG("Too many data points!");
2572
2573 /* Allocate... */
2574 gsl_fft_complex_wavetable *wavetable =
2575 gsl_fft_complex_wavetable_alloc((size_t) n);
2576 gsl_fft_complex_workspace *workspace =
2577 gsl_fft_complex_workspace_alloc((size_t) n);
2578
2579 /* Set data (real, complex)... */
2580 for (int i = 0; i < n; i++) {
2581 data[2 * i] = fcReal[i];
2582 data[2 * i + 1] = fcImag[i];
2583 }
2584
2585 /* Calculate FFT... */
2586 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
2587
2588 /* Copy data... */
2589 for (int i = 0; i < n; i++) {
2590 fcReal[i] = data[2 * i];
2591 fcImag[i] = data[2 * i + 1];
2592 }
2593
2594 /* Free... */
2595 gsl_fft_complex_wavetable_free(wavetable);
2596 gsl_fft_complex_workspace_free(workspace);
2597}
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:339

◆ geo2cart()

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

Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates.

This function converts geographic coordinates specified by longitude, latitude, and altitude into Cartesian coordinates. The Earth is approximated as a sphere with radius defined by the constant RE.

Parameters
zThe altitude above the Earth's surface in kilometers.
lonThe longitude in degrees.
latThe latitude in degrees.
xPointer to an array of three doubles where the computed Cartesian coordinates (x, y, z) will be stored.

The function computes the Cartesian coordinates using the given altitude, longitude, and latitude. It assumes the Earth is a perfect sphere and uses the following formulas:

  • \( x = (\textrm{radius}) \cos(\textrm{lat in radians}) \cos(\textrm{lon in radians}) \)
  • \( y = (\textrm{radius}) \cos(\textrm{lat in radians}) \sin(\textrm{lon in radians}) \)
  • \( z = (\textrm{radius}) \sin(\textrm{lat in radians}) \)
Note
The constant RE is defined as the Earth's radius in kilometers.
Longitude and latitude should be in degrees.
See also
https://en.wikipedia.org/wiki/Geographic_coordinate_conversion
Author
Lars Hoffmann

Definition at line 2601 of file mptrac.c.

2605 {
2606
2607 const double radius = z + RE;
2608 const double latrad = DEG2RAD(lat);
2609 const double lonrad = DEG2RAD(lon);
2610 const double coslat = cos(latrad);
2611
2612 x[0] = radius * coslat * cos(lonrad);
2613 x[1] = radius * coslat * sin(lonrad);
2614 x[2] = radius * sin(latrad);
2615}

◆ get_met_filename()

void get_met_filename ( const ctl_t ctl,
const double  t,
const int  direct,
const char *  metbase,
const double  dt_met,
char *  filename 
)

Generates a formatted filename for meteorological data files based on the input parameters.

This function determines a rounded time interval, decodes the time components (year, month, day, hour, minute, second), and constructs a filename string for meteorological data files in various formats. The filename is adjusted based on the input control settings.

Parameters
[in]ctlPointer to the control structure containing configuration settings.
[in]tThe time value in seconds since a reference epoch.
[in]directDirection to round the time value. Use -1 for rounding down and 1 for rounding up.
[in]metbaseBase string for the filename, representing the dataset.
[in]dt_metTime interval for rounding in seconds.
[out]filenameOutput buffer to store the generated filename.
Note
The function modifies the provided filename buffer to include placeholders (e.g., YYYY, MM, DD, HH) replaced with the corresponding time values. The format of the filename depends on the values in the control structure (e.g., ctl->met_type).
Warning
Ensure that the filename buffer has sufficient size to accommodate the resulting string.
Author
Lars Hoffmann

Definition at line 2619 of file mptrac.c.

2625 {
2626
2627 char repl[LEN];
2628
2629 double t6, r;
2630
2631 int year, mon, day, hour, min, sec;
2632
2633 /* Round time to fixed intervals... */
2634 if (direct == -1)
2635 t6 = floor(t / dt_met) * dt_met;
2636 else
2637 t6 = ceil(t / dt_met) * dt_met;
2638
2639 /* Decode time... */
2640 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
2641
2642 /* Set filename of MPTRAC meteo files... */
2643 if (ctl->met_clams == 0) {
2644 if (ctl->met_type == 0)
2645 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
2646 else if (ctl->met_type == 1)
2647 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
2648 else if (ctl->met_type == 2)
2649 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
2650 else if (ctl->met_type == 3)
2651 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
2652 else if (ctl->met_type == 4)
2653 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
2654 else if (ctl->met_type == 5)
2655 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
2656 else if (ctl->met_type == 7)
2657 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
2658 else if (ctl->met_type == 8)
2659 sprintf(filename, "%s_YYYY_MM_DD_HH.lz4", metbase);
2660 sprintf(repl, "%d", year);
2661 get_met_replace(filename, "YYYY", repl);
2662 sprintf(repl, "%02d", mon);
2663 get_met_replace(filename, "MM", repl);
2664 sprintf(repl, "%02d", day);
2665 get_met_replace(filename, "DD", repl);
2666 sprintf(repl, "%02d", hour);
2667 get_met_replace(filename, "HH", repl);
2668 }
2669
2670 /* Set filename of CLaMS meteo files... */
2671 else {
2672 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
2673 sprintf(repl, "%d", year);
2674 get_met_replace(filename, "YYYY", repl);
2675 sprintf(repl, "%02d", year % 100);
2676 get_met_replace(filename, "YY", repl);
2677 sprintf(repl, "%02d", mon);
2678 get_met_replace(filename, "MM", repl);
2679 sprintf(repl, "%02d", day);
2680 get_met_replace(filename, "DD", repl);
2681 sprintf(repl, "%02d", hour);
2682 get_met_replace(filename, "HH", repl);
2683 }
2684}
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:3265
void get_met_replace(char *orig, const char *search, const char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:2688
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2657
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=ZFP, 4=ZSTD, 5=cms, 6=grib,...
Definition: mptrac.h:2654
Here is the call graph for this function:

◆ get_met_replace()

void get_met_replace ( char *  orig,
const char *  search,
const char *  repl 
)

Replaces occurrences of a substring in a string with another substring.

This function replaces occurrences of the substring search in the string orig with the substring repl. The replacement is performed in-place.

Parameters
origThe original string where replacements are to be made.
searchThe substring to be replaced.
replThe substring to replace occurrences of search.

The function iterates over the original string orig and replaces each occurrence of the substring search with the substring repl. It performs the replacement operation up to three times to ensure multiple occurrences are replaced.

Note
We use this function to repace the strings YYYY, MM, and DD by year, month, and day in filenames.
Ensure that orig, search, and repl are properly initialized and have sufficient memory allocated before calling this function.
Author
Lars Hoffmann

Definition at line 2688 of file mptrac.c.

2691 {
2692
2693 char buffer[LEN];
2694
2695 /* Iterate... */
2696 for (int i = 0; i < 3; i++) {
2697
2698 /* Replace sub-string... */
2699 char *ch;
2700 if (!(ch = strstr(orig, search)))
2701 return;
2702 strncpy(buffer, orig, (size_t) (ch - orig));
2703 buffer[ch - orig] = 0;
2704 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
2705 orig[0] = 0;
2706 strcpy(orig, buffer);
2707 }
2708}

◆ get_tropo()

void get_tropo ( const int  met_tropo,
ctl_t ctl,
const clim_t clim,
met_t met,
const double *  lons,
const int  nx,
const double *  lats,
const int  ny,
double *  pt,
double *  zt,
double *  tt,
double *  qt,
double *  o3t,
double *  ps,
double *  zs 
)

Calculate tropopause data.

This function reads and interpolates various meteorological parameters such as tropopause pressure, temperature, and ozone concentration at specified latitudes and longitudes. The interpolated data is stored in the provided arrays.

Parameters
met_tropoAn integer specifying the type of meteorological data to use.
ctlPointer to a ctl_t structure that controls the meteorological data processing.
climPointer to a clim_t structure containing climatological data.
metPointer to a met_t structure containing meteorological data.
lonsArray of longitudes at which to interpolate data. The array should have nx elements.
nxNumber of longitude points.
latsArray of latitudes at which to interpolate data. The array should have ny elements.
nyNumber of latitude points.
ptPointer to an array where the interpolated pressure values will be stored. The array should have nx * ny elements.
ztPointer to an array where the interpolated height values will be stored. The array should have nx * ny elements.
ttPointer to an array where the interpolated temperature values will be stored. The array should have nx * ny elements.
qtPointer to an array where the interpolated specific humidity values will be stored. The array should have nx * ny elements.
o3tPointer to an array where the interpolated ozone concentration values will be stored. The array should have nx * ny elements.
psPointer to an array where the interpolated surface pressure values will be stored. The array should have nx * ny elements.
zsPointer to an array where the interpolated surface height values will be stored. The array should have nx * ny elements.
Precondition
lons must have at least nx elements.
lats must have at least ny elements.
pt, zt, tt, qt, o3t, ps, and zs must have at least nx * ny elements.
Postcondition
The arrays pt, zt, tt, qt, o3t, ps, and zs will contain the interpolated meteorological data.
Note
The function utilizes OpenMP for parallel processing of the interpolation tasks.
The function uses the auxiliary functions read_met_tropo, intpol_met_space_2d, and intpol_met_space_3d for reading and interpolating the tropopause data.
Author
Lars Hoffmann

Definition at line 2712 of file mptrac.c.

2727 {
2728
2730
2731 ctl->met_tropo = met_tropo;
2732 read_met_tropo(ctl, clim, met);
2733#pragma omp parallel for default(shared) private(ci,cw)
2734 for (int ix = 0; ix < nx; ix++)
2735 for (int iy = 0; iy < ny; iy++) {
2736 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2737 &pt[iy * nx + ix], ci, cw, 1);
2738 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2739 &ps[iy * nx + ix], ci, cw, 0);
2740 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2741 &zs[iy * nx + ix], ci, cw, 0);
2742 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2743 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2744 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2745 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2746 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2747 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2748 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2749 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2750 }
2751}
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:3048
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:11835
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:2985
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:964
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2778
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3727
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3637
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3643
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3730
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3712
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3670
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3709
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 2755 of file mptrac.c.

2763 {
2764
2765 /* Check longitude... */
2766 *lon2 = FMOD(lon, 360.);
2767 if (*lon2 < lons[0])
2768 *lon2 += 360;
2769 else if (*lon2 > lons[nlon - 1])
2770 *lon2 -= 360;
2771
2772 /* Check latitude... */
2773 *lat2 = lat;
2774 if (lats[0] < lats[nlat - 1])
2775 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
2776 else
2777 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
2778}

◆ intpol_check_cartesian()

void intpol_check_cartesian ( const double *  lons,
const int  nlon,
const double *  lats,
const int  nlat,
const double  lon,
const double  lat,
double *  lon2,
double *  lat2 
)

Clamps UTM coordinates to the valid bounds.

This function constrains the given UTM easting and northing values so they remain within the limits defined by the provided x and y coordinate arrays.

Parameters
[in]lonsPointer to an array of valid x/easting values.
[in]nlonNumber of elements in the x/easting array.
[in]latsPointer to an array of valid y/northing values.
[in]nlatNumber of elements in the y/northing array.
[in]lonInput x/easting coordinate to be checked and adjusted.
[in]latInput y/northing coordinate to be checked and adjusted.
[out]lon2Pointer to the adjusted x/easting coordinate.
[out]lat2Pointer to the adjusted y/northing coordinate.
Author
Robin Brase

Definition at line 2782 of file mptrac.c.

2790 {
2791
2792 *lon2 = lon;
2793 if (lons[0] < lons[nlon - 1])
2794 *lon2 = MIN(MAX(lon, lons[0]), lons[nlon - 1]);
2795 else
2796 *lon2 = MIN(MAX(lon, lons[nlon - 1]), lons[0]);
2797
2798 *lat2 = lat;
2799 if (lats[0] < lats[nlat - 1])
2800 *lat2 = MIN(MAX(lat, lats[0]), lats[nlat - 1]);
2801 else
2802 *lat2 = MIN(MAX(lat, lats[nlat - 1]), lats[0]);
2803}

◆ intpol_met_4d_zeta()

void intpol_met_4d_zeta ( const met_t met0,
float  height0[EX][EY][EP],
float  array0[EX][EY][EP],
const met_t met1,
float  height1[EX][EY][EP],
float  array1[EX][EY][EP],
const double  ts,
const double  height,
const double  lon,
const double  lat,
double *  var,
int *  ci,
double *  cw,
const int  init 
)

Interpolates meteorological variables to a given position and time.

This function interpolates meteorological variables to a specified position and time. It calculates the interpolated value based on the values provided at two time steps and performs interpolation in time, longitude, latitude, and altitude dimensions.

Parameters
met0Pointer to the meteorological data at the first time step.
height0Array containing heights at the first time step.
array0Array containing meteorological variable values at the first time step.
met1Pointer to the meteorological data at the second time step.
height1Array containing heights at the second time step.
array1Array containing meteorological variable values at the second time step.
tsInterpolation time (fractional time between met0 and met1).
heightAltitude at which to interpolate.
lonLongitude at which to interpolate.
latLatitude at which to interpolate.
varPointer to store the interpolated variable value.
ciArray to store the calculated indices.
cwArray to store the weighting factors.
initFlag indicating if it's the first call (1) or not (0).

The function first restricts the longitude within the range [0, 360) degrees. It then calculates the horizontal indices (ci[0] and ci[1]) based on the provided longitude and latitude. Next, it locates the vertical indices for each edge of the column based on the provided height.

The function then calculates the weighting factors for time, longitude, latitude, and altitude. It iterates over the interpolation process to determine the altitude weighting factor. After initializing the interpolation parameters, it calculates the interpolated variable value and stores it in the memory location pointed to by var.

Note
Ensure that all arrays (height0, array0, height1, array1, ci, cw) have sufficient memory allocated before calling this function.
Author
Jan Clemens

Definition at line 2808 of file mptrac.c.

2822 {
2823
2824 if (init) {
2825
2826 /* Check longitude and latitude... */
2827 double lon2, lat2;
2828
2829 if (met0->coord_type == 0)
2830 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
2831 &lon2, &lat2);
2832 else
2833 intpol_check_cartesian(met0->lon, met0->nx, met0->lat, met0->ny, lon,
2834 lat, &lon2, &lat2);
2835
2836 /* Get horizontal indizes... */
2837 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
2838 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
2839
2840 /* Locate the vertical indizes for each edge of the column... */
2841 int ind[2][4];
2842 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
2843 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
2844
2845 /* Find minimum and maximum indizes... */
2846 ci[2] = ind[0][0];
2847 int k_max = ind[0][0];
2848 for (int i = 0; i < 2; i++)
2849 for (int j = 0; j < 4; j++) {
2850 if (ci[2] > ind[i][j])
2851 ci[2] = ind[i][j];
2852 if (k_max < ind[i][j])
2853 k_max = ind[i][j];
2854 }
2855
2856 /* Get weighting factors for time, longitude and latitude... */
2857 cw[3] = (ts - met0->time) / (met1->time - met0->time);
2858 cw[0] = (lon2 - met0->lon[ci[0]]) /
2859 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
2860 cw[1] = (lat2 - met0->lat[ci[1]]) /
2861 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
2862
2863 /* Interpolate in time at the lowest level... */
2864 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
2865 - heights0[ci[0]][ci[1]][ci[2]])
2866 + heights0[ci[0]][ci[1]][ci[2]];
2867 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
2868 - heights0[ci[0]][ci[1] + 1][ci[2]])
2869 + heights0[ci[0]][ci[1] + 1][ci[2]];
2870 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
2871 - heights0[ci[0] + 1][ci[1]][ci[2]])
2872 + heights0[ci[0] + 1][ci[1]][ci[2]];
2873 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
2874 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
2875 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
2876
2877 /* Interpolate in latitude direction... */
2878 double height0 = cw[1] * (height01 - height00) + height00;
2879 double height1 = cw[1] * (height11 - height10) + height10;
2880
2881 /* Interpolate in longitude direction... */
2882 double height_bot = cw[0] * (height1 - height0) + height0;
2883
2884 /* Interpolate in time at the upper level... */
2885 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2886 - heights0[ci[0]][ci[1]][ci[2] + 1])
2887 + heights0[ci[0]][ci[1]][ci[2] + 1];
2888 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2889 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2890 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2891 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2892 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2893 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2894 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2895 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2896 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2897
2898 /* Interpolate in latitude direction... */
2899 height0 = cw[1] * (height01 - height00) + height00;
2900 height1 = cw[1] * (height11 - height10) + height10;
2901
2902 /* Interpolate in longitude direction... */
2903 double height_top = cw[0] * (height1 - height0) + height0;
2904
2905 /* Search at higher levels if height is not in box... */
2906 while (((heights0[0][0][0] > heights0[0][0][1]) &&
2907 ((height_bot <= height) || (height_top > height))
2908 && (height_bot >= height) && (ci[2] < k_max))
2909 ||
2910 ((heights0[0][0][0] < heights0[0][0][1]) &&
2911 ((height_bot >= height) || (height_top < height))
2912 && (height_bot <= height) && (ci[2] < k_max))
2913 ) {
2914
2915 ci[2]++;
2916 height_bot = height_top;
2917
2918 /* Interpolate in time at the next level... */
2919 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2920 - heights0[ci[0]][ci[1]][ci[2] + 1])
2921 + heights0[ci[0]][ci[1]][ci[2] + 1];
2922 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2923 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2924 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2925 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2926 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2927 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2928 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2929 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2930 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2931
2932 /* Interpolate in latitude direction... */
2933 height0 = cw[1] * (height01 - height00) + height00;
2934 height1 = cw[1] * (height11 - height10) + height10;
2935
2936 /* Interpolate in longitude direction... */
2937 height_top = cw[0] * (height1 - height0) + height0;
2938 }
2939
2940 /* Get vertical weighting factors... */
2941 cw[2] = (height - height_bot)
2942 / (height_top - height_bot);
2943 }
2944
2945 /* Calculate the needed array values... */
2946 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
2947 - array0[ci[0]][ci[1]][ci[2]])
2948 + array0[ci[0]][ci[1]][ci[2]];
2949 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
2950 - array0[ci[0] + 1][ci[1]][ci[2]])
2951 + array0[ci[0] + 1][ci[1]][ci[2]];
2952 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
2953 - array0[ci[0]][ci[1] + 1][ci[2]])
2954 + array0[ci[0]][ci[1] + 1][ci[2]];
2955 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
2956 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
2957 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
2958 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
2959 - array0[ci[0]][ci[1]][ci[2] + 1])
2960 + array0[ci[0]][ci[1]][ci[2] + 1];
2961 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2962 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2963 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2964 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2965 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2966 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2967 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2968 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2969 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2970
2971 const double array00 = cw[0] * (array100 - array000) + array000;
2972 const double array10 = cw[0] * (array110 - array010) + array010;
2973 const double array01 = cw[0] * (array101 - array001) + array001;
2974 const double array11 = cw[0] * (array111 - array011) + array011;
2975
2976 const double aux0 = cw[1] * (array10 - array00) + array00;
2977 const double aux1 = cw[1] * (array11 - array01) + array01;
2978
2979 /* Interpolate vertically... */
2980 *var = cw[2] * (aux1 - aux0) + aux0;
2981}
void intpol_check_cartesian(const double *lons, const int nlon, const double *lats, const int nlat, const double lon, const double lat, double *lon2, double *lat2)
Clamps UTM coordinates to the valid bounds.
Definition: mptrac.c:2782
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:3578
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:2755
int coord_type
Definition: mptrac.h:3601
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3616
int npl
Number of model levels.
Definition: mptrac.h:3613
double time
Time [s].
Definition: mptrac.h:3598
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3619
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 2985 of file mptrac.c.

2994 {
2995
2996 /* Initialize interpolation... */
2997 if (init) {
2998
2999 /* Check longitude and latitude... */
3000 double lon2, lat2;
3001
3002 if (met->coord_type == 0)
3003 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
3004 &lon2, &lat2);
3005 else
3006 intpol_check_cartesian(met->lon, met->nx, met->lat, met->ny, lon, lat,
3007 &lon2, &lat2);
3008
3009 /* Get interpolation indices... */
3010 ci[0] = locate_irr(met->p, met->np, p);
3011 ci[1] = locate_reg(met->lon, met->nx, lon2);
3012 ci[2] = locate_irr(met->lat, met->ny, lat2);
3013
3014 /* Get interpolation weights... */
3015 cw[0] = (met->p[ci[0] + 1] - p)
3016 / (met->p[ci[0] + 1] - met->p[ci[0]]);
3017 cw[1] = (met->lon[ci[1] + 1] - lon2)
3018 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
3019 cw[2] = (met->lat[ci[2] + 1] - lat2)
3020 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
3021 }
3022
3023 /* Interpolate vertically... */
3024 const double aux00 =
3025 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
3026 + array[ci[1]][ci[2]][ci[0] + 1];
3027 const double aux01 =
3028 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
3029 array[ci[1]][ci[2] + 1][ci[0] + 1])
3030 + array[ci[1]][ci[2] + 1][ci[0] + 1];
3031 const double aux10 =
3032 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
3033 array[ci[1] + 1][ci[2]][ci[0] + 1])
3034 + array[ci[1] + 1][ci[2]][ci[0] + 1];
3035 const double aux11 =
3036 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
3037 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
3038 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
3039
3040 /* Interpolate horizontally... */
3041 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
3042 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
3043 *var = cw[1] * (aux0 - aux1) + aux1;
3044}
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 3048 of file mptrac.c.

3056 {
3057
3058 /* Initialize interpolation... */
3059 if (init) {
3060
3061 /* Check longitude and latitude... */
3062 double lon2, lat2;
3063
3064 if (met->coord_type == 0)
3065 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
3066 &lon2, &lat2);
3067 else
3068 intpol_check_cartesian(met->lon, met->nx, met->lat, met->ny, lon, lat,
3069 &lon2, &lat2);
3070
3071
3072 /* Get interpolation indices... */
3073 ci[1] = locate_reg(met->lon, met->nx, lon2);
3074 ci[2] = locate_irr(met->lat, met->ny, lat2);
3075
3076 /* Get interpolation weights... */
3077 cw[1] = (met->lon[ci[1] + 1] - lon2)
3078 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
3079 cw[2] = (met->lat[ci[2] + 1] - lat2)
3080 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
3081 }
3082
3083 /* Set variables... */
3084 const double aux00 = array[ci[1]][ci[2]];
3085 const double aux01 = array[ci[1]][ci[2] + 1];
3086 const double aux10 = array[ci[1] + 1][ci[2]];
3087 const double aux11 = array[ci[1] + 1][ci[2] + 1];
3088
3089 /* Interpolate horizontally... */
3090 if (isfinite(aux00) && isfinite(aux01)
3091 && isfinite(aux10) && isfinite(aux11)) {
3092 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
3093 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
3094 *var = cw[1] * (aux0 - aux1) + aux1;
3095 } else {
3096 if (cw[2] < 0.5) {
3097 if (cw[1] < 0.5)
3098 *var = aux11;
3099 else
3100 *var = aux01;
3101 } else {
3102 if (cw[1] < 0.5)
3103 *var = aux10;
3104 else
3105 *var = aux00;
3106 }
3107 }
3108}
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 3112 of file mptrac.c.

3124 {
3125
3126 double var0, var1;
3127
3128 /* Spatial interpolation... */
3129 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
3130 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
3131
3132 /* Get weighting factor... */
3133 const double wt = (met1->time - ts) / (met1->time - met0->time);
3134
3135 /* Interpolate... */
3136 *var = wt * (var0 - var1) + var1;
3137}
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 3141 of file mptrac.c.

3152 {
3153
3154 double var0, var1;
3155
3156 /* Spatial interpolation... */
3157 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
3158 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
3159
3160 /* Get weighting factor... */
3161 const double wt = (met1->time - ts) / (met1->time - met0->time);
3162
3163 /* Interpolate... */
3164 if (isfinite(var0) && isfinite(var1))
3165 *var = wt * (var0 - var1) + var1;
3166 else if (wt < 0.5)
3167 *var = var1;
3168 else
3169 *var = var0;
3170}
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 3174 of file mptrac.c.

3188 {
3189
3190 double mean = 0;
3191
3192 int n = 0;
3193
3194 /* Check longitude and latitude... */
3195 double lon2, lat2;
3196 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
3197
3198 /* Get indices... */
3199 const int ix = locate_reg(lons, (int) nlon, lon2);
3200 const int iy = locate_irr(lats, (int) nlat, lat2);
3201
3202 /* Calculate standard deviation... */
3203 *sigma = 0;
3204 for (int dx = 0; dx < 2; dx++)
3205 for (int dy = 0; dy < 2; dy++) {
3206 if (isfinite(array0[ix + dx][iy + dy])) {
3207 mean += array0[ix + dx][iy + dy];
3208 *sigma += SQR(array0[ix + dx][iy + dy]);
3209 n++;
3210 }
3211 if (isfinite(array1[ix + dx][iy + dy])) {
3212 mean += array1[ix + dx][iy + dy];
3213 *sigma += SQR(array1[ix + dx][iy + dy]);
3214 n++;
3215 }
3216 }
3217 if (n > 0)
3218 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
3219
3220 /* Linear interpolation... */
3221 if (method == 1 && isfinite(array0[ix][iy])
3222 && isfinite(array0[ix][iy + 1])
3223 && isfinite(array0[ix + 1][iy])
3224 && isfinite(array0[ix + 1][iy + 1])
3225 && isfinite(array1[ix][iy])
3226 && isfinite(array1[ix][iy + 1])
3227 && isfinite(array1[ix + 1][iy])
3228 && isfinite(array1[ix + 1][iy + 1])) {
3229
3230 const double aux00 = LIN(lons[ix], array0[ix][iy],
3231 lons[ix + 1], array0[ix + 1][iy], lon2);
3232 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
3233 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
3234 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
3235
3236 const double aux10 = LIN(lons[ix], array1[ix][iy],
3237 lons[ix + 1], array1[ix + 1][iy], lon2);
3238 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
3239 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
3240 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
3241
3242 *var = LIN(time0, aux0, time1, aux1, time);
3243 }
3244
3245 /* Nearest neighbor interpolation... */
3246 else {
3247 const double aux00 = NN(lons[ix], array0[ix][iy],
3248 lons[ix + 1], array0[ix + 1][iy], lon2);
3249 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
3250 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
3251 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
3252
3253 const double aux10 = NN(lons[ix], array1[ix][iy],
3254 lons[ix + 1], array1[ix + 1][iy], lon2);
3255 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
3256 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
3257 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
3258
3259 *var = NN(time0, aux0, time1, aux1, time);
3260 }
3261}
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1517
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 3265 of file mptrac.c.

3273 {
3274
3275 struct tm t0, *t1;
3276
3277 t0.tm_year = 100;
3278 t0.tm_mon = 0;
3279 t0.tm_mday = 1;
3280 t0.tm_hour = 0;
3281 t0.tm_min = 0;
3282 t0.tm_sec = 0;
3283
3284 const time_t jsec0 = (time_t) jsec + timegm(&t0);
3285 t1 = gmtime(&jsec0);
3286
3287 *year = t1->tm_year + 1900;
3288 *mon = t1->tm_mon + 1;
3289 *day = t1->tm_mday;
3290 *hour = t1->tm_hour;
3291 *min = t1->tm_min;
3292 *sec = t1->tm_sec;
3293 *remain = jsec - floor(jsec);
3294}

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

3302 {
3303
3304 /* Check number of data points... */
3305 if (nk < 2)
3306 return 1.0;
3307
3308 /* Get altitude... */
3309 const double z = Z(p);
3310
3311 /* Get weighting factor... */
3312 if (z < kz[0])
3313 return kw[0];
3314 else if (z > kz[nk - 1])
3315 return kw[nk - 1];
3316 else {
3317 const int idx = locate_irr(kz, nk, z);
3318 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
3319 }
3320}
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 3324 of file mptrac.c.

3326 {
3327
3328 /*
3329 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
3330 and water vapor volume mixing ratio [1].
3331
3332 Reference: https://en.wikipedia.org/wiki/Lapse_rate
3333 */
3334
3335 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
3336
3337 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
3338}
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:310
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1814
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:275
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:265
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:260
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:255

◆ level_definitions()

void level_definitions ( ctl_t ctl)

Defines pressure levels for meteorological data.

This function defines pressure levels for meteorological data based on the given control structure (ctl). Pressure levels are defined differently based on the value of met_press_level_def in ctl.

Parameters
ctlControl structure containing information about pressure level definitions.

The function determines the number of pressure levels (met_np) and the corresponding pressure values (met_p) based on the value of met_press_level_def in the control structure ctl. It initializes the met_np and met_p fields accordingly.

Note
Valid values for met_press_level_def are:
  • 3: Define 147 pressure levels.
  • 4: Define 101 pressure levels.
  • 5: Define 62 pressure levels.
  • 6: Define 137 pressure levels.
  • 7: Define 59 pressure levels. Values 0, 1, and 2 are disabled and any other value will result in an error message.
Author
Jan Clemens

Definition at line 3342 of file mptrac.c.

3343 {
3344
3345 if (0 == ctl->met_press_level_def) {
3346
3347 ERRMSG
3348 ("MET_PRESS_LEVEL_DEF=0 is disabled. Use 3 for the extended L137 set.");
3349
3350 } else if (1 == ctl->met_press_level_def) {
3351
3352 ERRMSG
3353 ("MET_PRESS_LEVEL_DEF=1 is disabled. Use 4 for the extended L91 set.");
3354
3355 } else if (2 == ctl->met_press_level_def) {
3356
3357 ERRMSG
3358 ("MET_PRESS_LEVEL_DEF=2 is disabled. Use 5 for the extended L60 set.");
3359
3360 } else if (3 == ctl->met_press_level_def) {
3361
3362 ctl->met_np = 147;
3363
3364 const double press[147] = {
3365 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
3366 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
3367 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
3368 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
3369 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
3370 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
3371 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
3372 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
3373 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
3374 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
3375 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
3376 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
3377 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
3378 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
3379 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
3380 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
3381 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
3382 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
3383 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
3384 1031.97,
3385 1035.09, 1038.21, 1041.33, 1044.45
3386 };
3387
3388 for (int ip = 0; ip < ctl->met_np; ip++)
3389 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3390
3391 } else if (4 == ctl->met_press_level_def) {
3392
3393 ctl->met_np = 101;
3394
3395 const double press[101] = {
3396 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
3397 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
3398 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
3399 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
3400 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
3401 113.6382,
3402 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
3403 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
3404 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
3405 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
3406 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
3407 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
3408 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
3409 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
3410 1028.85, 1031.97,
3411 1035.09, 1038.21, 1041.33, 1044.45
3412 };
3413
3414 for (int ip = 0; ip < ctl->met_np; ip++)
3415 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3416
3417 } else if (5 == ctl->met_press_level_def) {
3418
3419 ctl->met_np = 62;
3420
3421 const double press[62] = {
3422 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
3423 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
3424 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
3425 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
3426 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
3427 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
3428 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
3429 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
3430 1044.45
3431 };
3432
3433 for (int ip = 0; ip < ctl->met_np; ip++)
3434 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3435
3436 } else if (6 == ctl->met_press_level_def) {
3437
3438 ctl->met_np = 137;
3439
3440 const double press[137] = {
3441 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
3442 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
3443 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
3444 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
3445 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
3446 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
3447 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
3448 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
3449 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
3450 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
3451 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
3452 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
3453 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
3454 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
3455 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
3456 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
3457 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
3458 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
3459 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
3460 1030.06, 1037.25, 1044.45
3461 };
3462
3463 for (int ip = 0; ip < ctl->met_np; ip++)
3464 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3465
3466 } else if (7 == ctl->met_press_level_def) {
3467
3468 ctl->met_np = 59;
3469
3470 const double press[59] = {
3471 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
3472 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
3473 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
3474 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
3475 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
3476 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
3477 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
3478 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
3479 1028.53, 1046.13
3480 };
3481
3482 for (int ip = 0; ip < ctl->met_np; ip++)
3483 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3484
3485 } else {
3486 ERRMSG("Use values between 3 and 7.");
3487 }
3488
3489 if (ctl->met_np > EP)
3490 ERRMSG("Recompile with larger EP to use this pressure level definition!");
3491}
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2744
int met_np
Number of target pressure levels.
Definition: mptrac.h:2738
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2741

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

3498 {
3499
3500 int ilo = 0;
3501 int ihi = n - 1;
3502 int i = (ihi + ilo) >> 1;
3503
3504 if (xx[i] < xx[i + 1])
3505 while (ihi > ilo + 1) {
3506 i = (ihi + ilo) >> 1;
3507 if (xx[i] > x)
3508 ihi = i;
3509 else
3510 ilo = i;
3511 } else
3512 while (ihi > ilo + 1) {
3513 i = (ihi + ilo) >> 1;
3514 if (xx[i] <= x)
3515 ihi = i;
3516 else
3517 ilo = i;
3518 }
3519
3520 return ilo;
3521}

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

3529 {
3530
3531 int ilo = 0;
3532 int ihi = n - 1;
3533 int i = (ihi + ilo) >> 1;
3534
3535 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
3536 return ig;
3537
3538 if (xx[i] < xx[i + 1])
3539 while (ihi > ilo + 1) {
3540 i = (ihi + ilo) >> 1;
3541 if (xx[i] > x)
3542 ihi = i;
3543 else
3544 ilo = i;
3545 } else
3546 while (ihi > ilo + 1) {
3547 i = (ihi + ilo) >> 1;
3548 if (xx[i] <= x)
3549 ihi = i;
3550 else
3551 ilo = i;
3552 }
3553
3554 return ilo;
3555}

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

3562 {
3563
3564 /* Calculate index... */
3565 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
3566
3567 /* Check range... */
3568 if (i < 0)
3569 return 0;
3570 else if (i > n - 2)
3571 return n - 2;
3572 else
3573 return i;
3574}

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

3584 {
3585
3586 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
3587 np, height_ap, 0);
3588 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
3589 np, height_ap, ind[0]);
3590 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
3591 np, height_ap, ind[1]);
3592 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
3593 np, height_ap, ind[2]);
3594}
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:3525
Here is the call graph for this function:

◆ module_advect()

void module_advect ( const ctl_t ctl,
const cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Advances particle positions using different advection schemes.

This function updates the positions of atmospheric particles using different advection schemes based on vertical velocity formulations (omega or zetadot). The advection is performed over a number of integration nodes, using meteorological data interpolated in time and space.

Parameters
[in]ctlPointer to the control structure containing configuration settings.
[in]cachePointer to the cache structure storing precomputed time step values.
[in]met0Pointer to the meteorological data structure at the initial time.
[in]met1Pointer to the meteorological data structure at the next time step.
[in,out]atmPointer to the atmospheric data structure containing particle states.
  • If ctl->advect_vert_coord is 0 or 2, the function uses omega vertical velocity.
  • If ctl->advect_vert_coord is 1, the function uses zetadot vertical velocity.
  • The function interpolates meteorological data either on pressure levels or model levels.
  • The advection scheme supports different integration methods (e.g., two-stage, four-stage).
  • The function updates longitude, latitude, and pressure (or zeta) for each particle.
  • Special handling is applied to ensure zeta values remain non-negative.
Author
Lars Hoffmann
Jan Clemens

Definition at line 3598 of file mptrac.c.

3603 {
3604
3605 /* Set timer... */
3606 SELECT_TIMER("MODULE_ADVECT", "PHYSICS");
3607
3608 /* Use omega vertical velocity... */
3609 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
3610
3611 /* Loop over particles... */
3612 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3613
3614 /* Init... */
3616 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
3617 x[3] = { 0, 0, 0 };
3618
3619 /* Loop over integration nodes... */
3620 for (int i = 0; i < ctl->advect; i++) {
3621
3622 /* Set position... */
3623 if (i == 0) {
3624 dts = 0.0;
3625 x[0] = atm->lon[ip];
3626 x[1] = atm->lat[ip];
3627 x[2] = atm->p[ip];
3628 } else {
3629 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3630 x[0] = atm->lon[ip] + DX2COORD(met0, dts * u[i - 1], atm->lat[ip]);
3631 x[1] = atm->lat[ip] + DY2COORD(met0, dts * v[i - 1]);
3632 x[2] = atm->p[ip] + dts * w[i - 1];
3633 }
3634 const double tm = atm->time[ip] + dts;
3635
3636 /* Interpolate meteo data on pressure levels... */
3637 if (ctl->advect_vert_coord == 0) {
3638 intpol_met_time_3d(met0, met0->u, met1, met1->u,
3639 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3640 intpol_met_time_3d(met0, met0->v, met1, met1->v,
3641 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3642 intpol_met_time_3d(met0, met0->w, met1, met1->w,
3643 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3644 }
3645
3646 /* Interpolate meteo data on model levels... */
3647 else {
3648 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
3649 met1, met1->pl, met1->ul,
3650 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3651 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
3652 met1, met1->pl, met1->vl,
3653 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3654 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
3655 met1, met1->pl, met1->wl,
3656 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3657 }
3658
3659 /* Get mean wind... */
3660 double k = 1.0;
3661 if (ctl->advect == 2)
3662 k = (i == 0 ? 0.0 : 1.0);
3663 else if (ctl->advect == 4)
3664 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3665 um += k * u[i];
3666 vm += k * v[i];
3667 wm += k * w[i];
3668 }
3669
3670 /* Set new position... */
3671 atm->time[ip] += cache->dt[ip];
3672 atm->lon[ip] += DX2COORD(met0, cache->dt[ip] * um,
3673 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3674 atm->lat[ip] += DY2COORD(met0, cache->dt[ip] * vm);
3675 atm->p[ip] += cache->dt[ip] * wm;
3676
3677 }
3678 }
3679
3680 /* Use zeta or eta vertical velocity... */
3681 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
3682
3683 /* Select quantity index depending on coordinate... */
3684 const int qnt = (ctl->advect_vert_coord == 1
3685 ? ctl->qnt_zeta : ctl->qnt_eta);
3686
3687 /* Loop over particles... */
3688 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3689
3690 /* Convert pressure to vertical coordinate (zeta or eta)... */
3692 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
3693 met1, met1->pl, met1->zetal,
3694 atm->time[ip], atm->p[ip],
3695 atm->lon[ip], atm->lat[ip],
3696 &atm->q[qnt][ip], ci, cw, 1);
3697
3698 /* Init... */
3699 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
3700 wdotm = 0, x[3] = { 0, 0, 0 };
3701
3702 /* Loop over integration nodes (Runge–Kutta steps)... */
3703 for (int i = 0; i < ctl->advect; i++) {
3704
3705 /* Set position... */
3706 if (i == 0) {
3707 dts = 0.0;
3708 x[0] = atm->lon[ip];
3709 x[1] = atm->lat[ip];
3710 x[2] = atm->q[qnt][ip];
3711 } else {
3712 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3713 x[0] = atm->lon[ip] + DX2COORD(met0, dts * u[i - 1], atm->lat[ip]);
3714 x[1] = atm->lat[ip] + DY2COORD(met0, dts * v[i - 1]);
3715 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
3716 }
3717
3718 const double tm = atm->time[ip] + dts;
3719
3720 /* Interpolate meteo data... */
3721 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
3722 met1, met1->zetal, met1->ul,
3723 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3724 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
3725 met1, met1->zetal, met1->vl,
3726 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3727 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
3728 met1, met1->zetal, met1->zeta_dotl,
3729 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
3730
3731 /* Compute Runge–Kutta weights... */
3732 double k = 1.0;
3733 if (ctl->advect == 2)
3734 k = (i == 0 ? 0.0 : 1.0);
3735 else if (ctl->advect == 4)
3736 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3737
3738 um += k * u[i];
3739 vm += k * v[i];
3740 wdotm += k * wdot[i];
3741 }
3742
3743 /* Update particle position... */
3744 atm->time[ip] += cache->dt[ip];
3745 atm->lon[ip] += DX2COORD(met0, cache->dt[ip] * um,
3746 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3747 atm->lat[ip] += DY2COORD(met0, cache->dt[ip] * vm);
3748 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
3749
3750 /* Convert vertical coordinate (zeta or eta) back to pressure... */
3751 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
3752 met1, met1->zetal, met1->pl,
3753 atm->time[ip],
3754 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
3755 &atm->p[ip], ci, cw, 1);
3756 }
3757 }
3758}
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:3112
void intpol_met_4d_zeta(const met_t *met0, float heights0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float heights1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double height, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological variables to a given position and time.
Definition: mptrac.c:2808
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1544
#define SELECT_TIMER(id, group)
Select and start a timer with specific attributes.
Definition: mptrac.h:2270
#define DX2COORD(met, dx, lat)
Convert a distance in meters to a coordinate value based on grid type.
Definition: mptrac.h:756
#define DY2COORD(met, dy)
Convert a distance to coordinate value based on grid type.
Definition: mptrac.h:779
double time[NP]
Time [s].
Definition: mptrac.h:3347
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3356
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3353
int np
Number of air parcels.
Definition: mptrac.h:3344
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3359
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3350
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3417
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2507
int advect
Advection scheme (1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2813
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2498
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:2817
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3763
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3721
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3757
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3754
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3715
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3751
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3718
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3748
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3760
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 3762 of file mptrac.c.

3767 {
3768
3769 /* Check parameters... */
3770 if (ctl->advect_vert_coord != 1)
3771 return;
3772
3773 /* Set timer... */
3774 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS");
3775
3776 /* Loop over particles... */
3777 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
3778
3779 /* Initialize pressure consistent with zeta... */
3781 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
3782 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
3783 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
3784 }
3785}
Here is the call graph for this function:

◆ module_bound_cond()

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

Apply boundary conditions to particles based on meteorological and climatological data.

This function applies boundary conditions to particles based on specified criteria, including latitude, pressure, surface layer parameters, and climatological data. It loops over each particle and checks whether it satisfies the specified boundary conditions. If a particle satisfies the conditions, its properties such as mass, volume mixing ratio, and age of air are updated accordingly.

It checks for quantity flags to determine which properties need to be updated. If the latitude or pressure of a particle falls outside the specified ranges, it skips the particle. It also considers surface layer parameters such as surface pressure, height, zeta range, and planetary boundary layer. If a particle is within the specified surface layer boundaries, its properties are updated accordingly.

The function updates properties such as mass and volume mixing ratio if the corresponding flags are set. It retrieves volume mixing ratio values for various trace gases (e.g., CFC-10, CFC-11, N2O, SF6) from climatological time series data and updates the particle properties accordingly. Additionally, it updates the age of air for each particle based on the current simulation time.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climatological data structure containing time series data.
met0Pointer to the meteorological data structure at the initial time step.
met1Pointer to the meteorological data structure at the next time step.
atmPointer to the atmospheric data structure containing particle information.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 3789 of file mptrac.c.

3795 {
3796
3797 /* Set timer... */
3798 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS");
3799
3800 /* Check quantity flags... */
3801 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
3802 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
3803 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
3804 return;
3805
3806 /* Loop over particles... */
3807 PARTICLE_LOOP(0, atm->np, 1,
3808 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3809
3810 /* Check latitude and pressure range... */
3811 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
3812 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
3813 continue;
3814
3815 /* Check surface layer... */
3816 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
3817 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
3818
3819 /* Get surface pressure... */
3820 double ps;
3822 INTPOL_2D(ps, 1);
3823
3824 /* Check pressure... */
3825 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
3826 continue;
3827
3828 /* Check height... */
3829 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
3830 continue;
3831
3832 /* Check zeta range... */
3833 if (ctl->bound_zetas > 0) {
3834 double t;
3835 INTPOL_3D(t, 1);
3836 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
3837 continue;
3838 }
3839
3840 /* Check planetary boundary layer... */
3841 if (ctl->bound_pbl) {
3842 double pbl;
3843 INTPOL_2D(pbl, 0);
3844 if (atm->p[ip] < pbl)
3845 continue;
3846 }
3847 }
3848
3849 /* Set mass and volume mixing ratio... */
3850 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
3851 atm->q[ctl->qnt_m][ip] =
3852 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
3853 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
3854 atm->q[ctl->qnt_vmr][ip] =
3855 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
3856
3857 /* Set CFC-10 volume mixing ratio... */
3858 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
3859 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
3860
3861 /* Set CFC-11 volume mixing ratio... */
3862 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
3863 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
3864
3865 /* Set CFC-12 volume mixing ratio... */
3866 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
3867 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
3868
3869 /* Set N2O volume mixing ratio... */
3870 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
3871 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
3872
3873 /* Set SF6 volume mixing ratio... */
3874 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
3875 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
3876
3877 /* Set age of air... */
3878 if (ctl->qnt_aoa >= 0)
3879 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
3880 }
3881}
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:396
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:995
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:2083
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:978
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3578
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3584
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3572
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3575
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3581
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2576
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2315
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2585
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2949
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2898
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2570
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2871
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2318
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2886
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2904
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2892
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2877
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2883
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2880
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2579
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2573
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2582
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2895
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2874
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2889
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2940
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2952
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2943
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2946
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2901
Here is the call graph for this function:

◆ module_chem_grid()

void module_chem_grid ( const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
const double  t 
)

Computes gridded chemical tracer concentrations (volume mixing ratio) from individual air parcel mass data and assigns them back to the parcels.

This function aggregates the mass of tracer particles onto a 3D chemical grid (longitude × latitude × altitude), accounting for either single or ensemble simulations depending on ctl->nens. It then interpolates meteorological temperature fields and computes volume mixing ratios, storing them in the specified tracer quantity (e.g., ctl->qnt_Cx).

If the molar mass is undefined or required quantity indices are missing, the function exits early.

Parallelization is supported via OpenMP or OpenACC.

Parameters
[in]ctlPointer to the control structure containing configuration parameters, including grid dimensions, tracer indices, and simulation mode.
[in]met0Pointer to the meteorological data at the beginning of the interpolation interval.
[in]met1Pointer to the meteorological data at the end of the interpolation interval.
[in,out]atmPointer to the atmospheric state, including parcel coordinates, time, mass, and output tracer fields.
[in]tCentral time step used for output and interpolation.
Note
  • Requires ctl->molmass > 0, and ctl->qnt_m and ctl->qnt_Cx to be set.
  • Uses ensemble mode if ctl->nens > 0 and assigns each parcel to its ensemble member via ctl->qnt_ens.
  • Grid box volume mixing ratios are computed assuming ideal gas law and a layered spherical grid.
  • The output quantity (e.g., qnt_Cx) is given in ppbv.
See also
intpol_met_time_3d()
P(), Z(), RHO()
ARRAY_3D macro
Author
Mingzhao Liu
Lars Hoffmann

Definition at line 3885 of file mptrac.c.

3890 {
3891
3892 if (met0->coord_type != 0)
3893 ERRMSG("Only lat/lon grid supported");
3894
3895 /* Check quantities... */
3896 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
3897 return;
3898 if (ctl->molmass <= 0)
3899 ERRMSG("Molar mass is not defined!");
3900
3901 /* Set timer... */
3902 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS");
3903
3904 /* Allocate... */
3905 const int ensemble_mode = (ctl->nens > 0);
3906 const int np = atm->np;
3907 const int nz = ctl->chemgrid_nz;
3908 const int nx = ctl->chemgrid_nx;
3909 const int ny = ctl->chemgrid_ny;
3910 const int ngrid = nx * ny * nz;
3911 const int nens = ensemble_mode ? ctl->nens : 1;
3912
3913 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
3914 double *restrict const press =
3915 (double *) malloc((size_t) nz * sizeof(double));
3916 double *restrict const mass =
3917 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
3918 double *restrict const area =
3919 (double *) malloc((size_t) ny * sizeof(double));
3920 double *restrict const lon =
3921 (double *) malloc((size_t) nx * sizeof(double));
3922 double *restrict const lat =
3923 (double *) malloc((size_t) ny * sizeof(double));
3924
3925 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3926 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3927 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3928
3929 /* Set grid box size... */
3930 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
3931 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
3932 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
3933
3934 /* Set vertical coordinates... */
3935#ifdef _OPENACC
3936#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np],z[0:nz],press[0:nz],mass[0:ngrid*nens],area[0:ny],lon[0:nx],lat[0:ny])
3937#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
3938#pragma acc parallel loop independent gang vector
3939#else
3940#pragma omp parallel for default(shared)
3941#endif
3942 for (int iz = 0; iz < nz; iz++) {
3943 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
3944 press[iz] = P(z[iz]);
3945 }
3946
3947 /* Set time interval for output... */
3948 const double t0 = tt - 0.5 * ctl->dt_mod;
3949 const double t1 = tt + 0.5 * ctl->dt_mod;
3950
3951 /* Get indices... */
3952#ifdef _OPENACC
3953#pragma acc parallel loop independent gang vector
3954#else
3955#pragma omp parallel for default(shared)
3956#endif
3957 for (int ip = 0; ip < np; ip++) {
3958 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
3959 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
3960 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
3961 if (atm->time[ip] < t0 || atm->time[ip] > t1
3962 || ixs[ip] < 0 || ixs[ip] >= nx
3963 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
3964 izs[ip] = -1;
3965 }
3966
3967 /* Set horizontal coordinates... */
3968#ifdef _OPENACC
3969#pragma acc parallel loop independent gang vector
3970#else
3971#pragma omp parallel for default(shared)
3972#endif
3973 for (int ix = 0; ix < nx; ix++)
3974 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3975
3976#ifdef _OPENACC
3977#pragma acc parallel loop independent gang vector
3978#else
3979#pragma omp parallel for default(shared)
3980#endif
3981 for (int iy = 0; iy < ny; iy++) {
3982 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3983 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3984 }
3985
3986 /* Get mass per grid box... */
3987#ifdef _OPENACC
3988#pragma acc parallel loop independent gang vector
3989#endif
3990 for (int ip = 0; ip < np; ip++) {
3991 if (izs[ip] >= 0) {
3992 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3993 if (ensemble_mode) {
3994 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3995 mass_idx += ens * ngrid;
3996 }
3997#ifdef _OPENACC
3998#pragma acc atomic update
3999#endif
4000 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
4001 }
4002 }
4003
4004 /* Assign grid data to air parcels ... */
4005#ifdef _OPENACC
4006#pragma acc parallel loop independent gang vector
4007#else
4008#pragma omp parallel for default(shared)
4009#endif
4010 for (int ip = 0; ip < np; ip++)
4011 if (izs[ip] >= 0) {
4012
4013 /* Interpolate temperature... */
4014 double temp;
4016 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
4017 press[izs[ip]],
4018 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
4019
4020 /* Set mass... */
4021 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
4022 if (ensemble_mode) {
4023 const int ens = (int) atm->q[ctl->qnt_ens][ip];
4024 mass_idx += ens * ngrid;
4025 }
4026
4027 /* Calculate volume mixing ratio... */
4028 const double m = mass[mass_idx];
4029 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
4030 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
4031 }
4032
4033 /* Free... */
4034#ifdef _OPENACC
4035#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
4036#endif
4037 free(mass);
4038 free(lon);
4039 free(lat);
4040 free(area);
4041 free(z);
4042 free(press);
4043 free(ixs);
4044 free(iys);
4045 free(izs);
4046}
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:499
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:290
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1574
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1751
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2910
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2997
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2994
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:3012
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:3015
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:3003
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:3006
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2621
int nens
Number of ensembles.
Definition: mptrac.h:3166
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2991
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:3000
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:3009
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2309
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2540
Here is the call graph for this function:

◆ module_chem_init()

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

Initializes the chemistry modules by setting atmospheric composition.

This function initializes various chemical components of the atmosphere using meteorological data and climatological information. It interpolates and sets values for water vapor (H2O), ozone (O3), and several radical species such as OH, HO2, H2O2, and O1D for each air parcel.

Parameters
ctlPointer to the control structure containing quantity flags.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climatology structure containing climatological data.
met0Pointer to the initial meteorological data structure.
met1Pointer to the final meteorological data structure.
atmPointer to the air parcel data structure.

The function uses OpenMP for parallel processing, iterating over each point in the atmosphere (atm->np) to initialize chemical species concentrations. It performs the following steps:

  • Interpolates H2O and O3 data from meteorological input if the respective quantity flags (ctl->qnt_Ch2o and ctl->qnt_Co3) are set.
  • Sets the concentrations of OH, HO2, H2O2, and O1D using climatological data if the respective quantity flags are set.
Author
Mingzhao Liu

Definition at line 4050 of file mptrac.c.

4056 {
4057
4058 /* Set timer... */
4059 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS");
4060
4061 /* Loop over particles... */
4062 PARTICLE_LOOP(0, atm->np, 0,
4063 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4064
4065 /* Set H2O and O3 using meteo data... */
4067 if (ctl->qnt_Ch2o >= 0) {
4068 double h2o;
4069 INTPOL_3D(h2o, 1);
4070 SET_ATM(qnt_Ch2o, h2o);
4071 }
4072 if (ctl->qnt_Co3 >= 0) {
4073 double o3;
4074 INTPOL_3D(o3, 1);
4075 SET_ATM(qnt_Co3, o3);
4076 }
4077
4078 /* Set radical species... */
4079 const double lat_ref =
4080 ctl->met_coord_type == 0 ? atm->lat[ip] : ctl->met_utm_ref_lat;
4081 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
4082 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4083 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
4084 lat_ref, atm->p[ip]));
4085 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
4086 lat_ref, atm->p[ip]));
4087 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
4088 lat_ref, atm->p[ip]));
4089 }
4090}
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:1770
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3566
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3569
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3563
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2543
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2546
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 4094 of file mptrac.c.

4099 {
4100
4101 /* Set timer... */
4102 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS");
4103
4104 /* Create random numbers... */
4105 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
4106
4107 /* Loop over particles... */
4108 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4109
4110 /* Interpolate surface pressure... */
4111 double ps;
4113 INTPOL_2D(ps, 1);
4114
4115 /* Initialize pressure range for vertical mixing... */
4116 double pbot = ps, ptop = ps;
4117
4118 /* Mixing in the PBL... */
4119 if (ctl->conv_mix_pbl) {
4120
4121 /* Interpolate PBL... */
4122 double pbl;
4123 INTPOL_2D(pbl, 0);
4124
4125 /* Set pressure range... */
4126 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
4127 }
4128
4129 /* Convective mixing... */
4130 if (ctl->conv_cape >= 0) {
4131
4132 /* Interpolate CAPE, CIN, and equilibrium level... */
4133 double cape, cin, pel;
4134 INTPOL_2D(cape, 0);
4135 INTPOL_2D(cin, 0);
4136 INTPOL_2D(pel, 0);
4137
4138 /* Set pressure range... */
4139 if (isfinite(cape) && cape >= ctl->conv_cape
4140 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
4141 ptop = GSL_MIN(ptop, pel);
4142 }
4143
4144 /* Apply vertical mixing... */
4145 if (ptop != pbot && atm->p[ip] >= ptop) {
4146
4147 /* Get density range... */
4148 double tbot, ttop;
4149 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
4150 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
4151 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
4152 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
4153 const double rhobot = pbot / tbot;
4154 const double rhotop = ptop / ttop;
4155
4156 /* Get new density... */
4157 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
4158
4159 /* Get pressure... */
4160 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
4161 }
4162 }
4163}
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:5566
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3414
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2862
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL pressure thickness).
Definition: mptrac.h:2859
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2856
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2865
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 4219 of file mptrac.c.

4223 {
4224
4225 /* Set timer... */
4226 SELECT_TIMER("MODULE_DECAY", "PHYSICS");
4227
4228 /* Check quantity flags... */
4229 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4230 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4231
4232 /* Loop over particles... */
4233 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
4234
4235 /* Get weighting factor... */
4236 const double w = tropo_weight(ctl, clim, atm, ip);
4237
4238 /* Set lifetime... */
4239 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
4240
4241 /* Calculate exponential decay... */
4242 const double aux = exp(-cache->dt[ip] / tdec);
4243 if (ctl->qnt_m >= 0) {
4244 if (ctl->qnt_mloss_decay >= 0)
4245 atm->q[ctl->qnt_mloss_decay][ip]
4246 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4247 atm->q[ctl->qnt_m][ip] *= aux;
4248 if (ctl->qnt_loss_rate >= 0)
4249 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
4250 }
4251 if (ctl->qnt_vmr >= 0)
4252 atm->q[ctl->qnt_vmr][ip] *= aux;
4253 }
4254}
double tropo_weight(const ctl_t *ctl, const clim_t *clim, const atm_t *atm, const int ip)
Computes a weighting factor based on tropopause pressure.
Definition: mptrac.c:12424
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2474
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2471
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2916
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2913
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 4258 of file mptrac.c.

4263 {
4264
4265 /* Set timer... */
4266 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS");
4267
4268 /* Create random numbers... */
4269 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4270
4271 /* Loop over particles... */
4272 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4273
4274 /* Get indices... */
4275 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
4276 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
4277 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
4278
4279 /* Get standard deviations of local wind data... */
4280 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
4281 for (int i = 0; i < 2; i++)
4282 for (int j = 0; j < 2; j++)
4283 for (int k = 0; k < 2; k++) {
4284 umean += met0->u[ix + i][iy + j][iz + k];
4285 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
4286 vmean += met0->v[ix + i][iy + j][iz + k];
4287 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
4288 wmean += met0->w[ix + i][iy + j][iz + k];
4289 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
4290
4291 umean += met1->u[ix + i][iy + j][iz + k];
4292 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
4293 vmean += met1->v[ix + i][iy + j][iz + k];
4294 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
4295 wmean += met1->w[ix + i][iy + j][iz + k];
4296 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
4297 }
4298 usig = usig / 16.f - SQR(umean / 16.f);
4299 usig = (usig > 0 ? sqrtf(usig) : 0);
4300 vsig = vsig / 16.f - SQR(vmean / 16.f);
4301 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
4302 wsig = wsig / 16.f - SQR(wmean / 16.f);
4303 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
4304
4305 /* Set temporal correlations for mesoscale fluctuations... */
4306 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
4307 const double r2 = sqrt(1 - r * r);
4308
4309 /* Calculate horizontal mesoscale wind fluctuations... */
4310 if (ctl->turb_mesox > 0) {
4311 cache->uvwp[ip][0] =
4312 (float) (r * cache->uvwp[ip][0] +
4313 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
4314 atm->lon[ip] +=
4315 DX2COORD(met0, cache->uvwp[ip][0] * cache->dt[ip], atm->lat[ip]);
4316
4317 cache->uvwp[ip][1] =
4318 (float) (r * cache->uvwp[ip][1] +
4319 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
4320 atm->lat[ip] += DY2COORD(met0, cache->uvwp[ip][1] * cache->dt[ip]);
4321 }
4322
4323 /* Calculate vertical mesoscale wind fluctuations... */
4324 if (ctl->turb_mesoz > 0) {
4325 cache->uvwp[ip][2] =
4326 (float) (r * cache->uvwp[ip][2] +
4327 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
4328 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
4329 }
4330 }
4331}
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3411
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2850
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2631
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2847
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 4335 of file mptrac.c.

4340 {
4341
4342 /* Set timer... */
4343 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS");
4344
4345 /* Create random numbers... */
4346 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4347
4348 /* Loop over particles... */
4349 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4350
4351 double pbl, ps, dsigw_dz = 0.0, sig_u = 0.0, sig_v = 0.0, sig_w = 0.0;
4352 double tau_u = 0.0, tau_v = 0.0, tau_w = 0.0;
4353
4354 /* Get PBL pressure... */
4356 INTPOL_2D(pbl, 1);
4357
4358 /* Let the background diffusion scheme handle particles above the PBL. */
4359 if (atm->p[ip] < pbl)
4360 continue;
4361
4362 /* Get surface pressure... */
4363 INTPOL_2D(ps, 0);
4364
4365 /* Skip invalid or vanishing PBL layers. */
4366 if (!(ps > 0.0 && pbl > 0.0 && ps > pbl))
4367 continue;
4368
4369 /* Calculate heights [m] above ground.
4370 Z() returns altitude in km, so multiply differences by 1e3. */
4371 const double p = MIN(atm->p[ip], ps);
4372 const double zs = Z(ps);
4373 const double z_raw = 1e3 * (Z(p) - zs);
4374 const double zi = 1e3 * (Z(pbl) - zs);
4375
4376 /* Require a physically meaningful PBL depth. */
4377 if (!(zi > 1.0))
4378 continue;
4379
4380 /* Clamp height to the PBL interval for closure evaluation. */
4381 const double z = CLAMP(z_raw, 0.0, zi);
4382 const double zeta = CLAMP(z / zi, 1e-6, 1.0 - 1e-6);
4383 const double z_m = MAX(z, 1.0);
4384
4385 /* Temporarily use clamped pressure for thermodynamic interpolation.
4386 This avoids inconsistent interpolation if a particle has slipped
4387 below the surface pressure. */
4388 const double p_save = atm->p[ip];
4389 atm->p[ip] = p;
4390
4391 /* Calculate friction velocity... */
4392 double ess, nss, h2o, t;
4393 INTPOL_2D(ess, 0);
4394 INTPOL_2D(nss, 0);
4395 INTPOL_3D(t, 1);
4396 INTPOL_3D(h2o, 0);
4397
4398 /* Restore particle pressure before any continue/update path. */
4399 atm->p[ip] = p_save;
4400
4401 const double tv = TVIRT(t, h2o);
4402 const double thetav = THETAVIRT(p, t, h2o);
4403 const double rho = RHO(p, tv);
4404 const double tau = sqrt(SQR(ess) + SQR(nss));
4405
4406 if (!(rho > 0.0))
4407 continue;
4408
4409 const double ustar = sqrt(MAX(tau / rho, 0.0));
4410 const double ust = MAX(1e-4, ustar);
4411
4412 /* Get surface sensible heat flux.
4413 Sign convention assumed here: unstable surface heating gives shf < 0,
4414 as in the existing implementation. */
4415 double shf;
4416 INTPOL_2D(shf, 1);
4417
4418 /* Estimate Monin-Obukhov length [m] to distinguish
4419 neutral, stable, and unstable cases. */
4420 double ol = 1e12;
4421 if (fabs(shf) > 1e-6)
4422 ol = thetav * rho * CPD * SQR(ust) * ust / (KARMAN * G0 * shf);
4423
4424 /* Neutral conditions... */
4425 if (zi / fabs(ol) < 1.0) {
4426
4427 /* corr has units of seconds, hence the exponential coefficients
4428 have units of s^-1. The derivative d(sig_w)/dz therefore needs
4429 the extra factor 1/ust. */
4430 const double corr = z_m / ust;
4431 const double sigw0 = 1.3 * ust * exp(-2e-4 * corr);
4432
4433 sig_u = MAX(2.0 * ust * exp(-3e-4 * corr), 1e-5);
4434 sig_v = MAX(sigw0, 1e-5);
4435 sig_w = MAX(sigw0, 1e-5);
4436 dsigw_dz = -2e-4 * sigw0 / ust;
4437
4438 tau_u = 0.5 * z_m / sig_w / (1.0 + 1.5e-3 * corr);
4439 tau_v = tau_u;
4440 tau_w = tau_u;
4441 }
4442
4443 /* Unstable conditions... */
4444 else if (ol < 0.0) {
4445
4446 /* Convective velocity scale [m/s]. */
4447 const double wstar_arg = -G0 / thetav * shf / (rho * CPD) * zi;
4448 const double wstar = pow(MAX(wstar_arg, 0.0), 1.0 / 3.0);
4449 double dsigw2_dz = 0.0;
4450
4451 /* Hanna1/FLEXPART turbulent velocity standard deviations [m/s]. */
4452 sig_u = MAX(ust * pow(MAX(12.0 - 0.5 * zi / ol, 0.0), 1.0 / 3.0), 1e-6);
4453 sig_v = sig_u;
4454
4455 if (zeta < 0.03) {
4456 const double arg = MAX(3.0 * zeta - ol / zi, 1e-12);
4457 sig_w = 0.96 * wstar * pow(arg, 1.0 / 3.0);
4458 dsigw2_dz = 1.8432 * SQR(wstar) / zi * pow(arg, -1.0 / 3.0);
4459 } else if (zeta < 0.4) {
4460 const double arg = MAX(3.0 * zeta - ol / zi, 1e-12);
4461 const double s1 = 0.96 * pow(arg, 1.0 / 3.0);
4462 const double s2 = 0.763 * pow(zeta, 0.175);
4463 if (s1 < s2) {
4464 sig_w = wstar * s1;
4465 dsigw2_dz = 1.8432 * SQR(wstar) / zi * pow(arg, -1.0 / 3.0);
4466 } else {
4467 sig_w = wstar * s2;
4468 dsigw2_dz = 0.203759 * SQR(wstar) / zi * pow(zeta, -0.65);
4469 }
4470 } else if (zeta < 0.96) {
4471 sig_w = 0.722 * wstar * pow(1.0 - zeta, 0.207);
4472 dsigw2_dz = -0.215812 * SQR(wstar) / zi * pow(1.0 - zeta, -0.586);
4473 } else {
4474 sig_w = 0.37 * wstar;
4475 dsigw2_dz = 0.0;
4476 }
4477
4478 sig_w = MAX(sig_w, 1e-6);
4479 dsigw_dz = sig_w > 1e-12 ? 0.5 * dsigw2_dz / sig_w : 0.0;
4480
4481 /* Hanna/FLEXPART Lagrangian timescales [s]. */
4482 tau_u = 0.15 * zi / MAX(sig_u, 1e-12);
4483 tau_v = tau_u;
4484
4485 if (z_m < fabs(ol)) {
4486 const double denom = 0.55 - 0.38 * fabs(z_m / ol);
4487 tau_w = 0.1 * z_m / (sig_w * MAX(denom, 0.05));
4488 } else if (zeta < 0.1)
4489 tau_w = 0.59 * z_m / sig_w;
4490 else
4491 tau_w = 0.15 * zi / sig_w * (1.0 - exp(-5.0 * zeta));
4492 }
4493
4494 /* Stable conditions... */
4495 else {
4496
4497 sig_u = MAX(2.0 * ust * (1.0 - zeta), 1e-6);
4498 sig_v = MAX(1.3 * ust * (1.0 - zeta), 1e-6);
4499 sig_w = MAX(1.3 * ust * (1.0 - zeta), 1e-6);
4500 dsigw_dz = -1.3 * ust / zi;
4501
4502 tau_u = 0.15 * zi / sig_u * sqrt(zeta);
4503 tau_v = 0.467 * tau_u;
4504 tau_w = 0.1 * zi / sig_w * pow(zeta, 0.8);
4505 }
4506
4507 /* Apply FLEXPART-consistent lower bounds for timescales. */
4508 tau_u = MAX(tau_u, 10.0);
4509 tau_v = MAX(tau_v, 10.0);
4510 tau_w = MAX(tau_w, 30.0);
4511
4512 /* Skip pathological states. */
4513 if (!(sig_u > 0.0 && sig_v > 0.0
4514 && sig_w > 0.0 && tau_u > 0.0 && tau_v > 0.0 && tau_w > 0.0))
4515 continue;
4516
4517 /* Update horizontal perturbation [m/s]. */
4518 const double dt = cache->dt[ip];
4519 const double dt_abs = fabs(dt);
4520
4521 const double ru = exp(-dt_abs / tau_u);
4522 const double ru2 = sqrt(MAX(0.0, 1.0 - SQR(ru)));
4523 const double rv = exp(-dt_abs / tau_v);
4524 const double rv2 = sqrt(MAX(0.0, 1.0 - SQR(rv)));
4525
4526 cache->uvwp[ip][0]
4527 = (float) (cache->uvwp[ip][0] * ru + sig_u * ru2 * cache->rs[3 * ip]);
4528
4529 cache->uvwp[ip][1]
4530 = (float) (cache->uvwp[ip][1] * rv
4531 + sig_v * rv2 * cache->rs[3 * ip + 1]);
4532
4533 /* Update vertical perturbation [m/s].
4534 The drift term is d(sig_w^2)/dz + sig_w^2/rho * d(rho)/dz.
4535 With exponential scale height H0 [km], dln(rho)/dz ~= -1/(1000 H0). */
4536 const double rw = exp(-dt_abs / tau_w);
4537 const double rw2 = sqrt(MAX(0.0, 1.0 - SQR(rw)));
4538 const double rhoaux = -1.0 / (1e3 * H0);
4539
4540 cache->uvwp[ip][2]
4541 = (float) (cache->uvwp[ip][2] * rw + sig_w * rw2 * cache->rs[3 * ip + 2]
4542 + tau_w * (1.0 - rw)
4543 * (2.0 * sig_w * dsigw_dz + rhoaux * SQR(sig_w)));
4544
4545 /* Calculate new horizontal air parcel position. */
4546 atm->lon[ip] += DX2COORD(met0, cache->uvwp[ip][0] * dt, atm->lat[ip]);
4547 atm->lat[ip] += DY2COORD(met0, cache->uvwp[ip][1] * dt);
4548
4549 /* Calculate new height and reflect robustly at surface and PBL top.
4550 Each boundary reflection reverses the vertical turbulent velocity.
4551 This loop is intentionally simple and explicit: it remains correct
4552 even if a large step crosses multiple boundaries. */
4553 double znew = z + cache->uvwp[ip][2] * dt;
4554
4555 while (znew < 0.0 || znew > zi) {
4556
4557 if (znew < 0.0) {
4558 znew = -znew;
4559 cache->uvwp[ip][2] = -cache->uvwp[ip][2];
4560 }
4561
4562 if (znew > zi) {
4563 znew = 2.0 * zi - znew;
4564 cache->uvwp[ip][2] = -cache->uvwp[ip][2];
4565 }
4566 }
4567
4568 /* Set pressure from reflected geometric height.
4569 This is more consistent than a linearized DZ2DP update for
4570 potentially large turbulent steps. */
4571 atm->p[ip] = P(zs + znew / 1000.0);
4572
4573 /* Enforce exact pressure limits of the local PBL column. */
4574 atm->p[ip] = CLAMP(atm->p[ip], pbl, ps);
4575 }
4576}
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1989
#define H0
Scale height [km].
Definition: mptrac.h:270
#define KARMAN
Karman's constant.
Definition: mptrac.h:280
#define CLAMP(v, lo, hi)
Clamp a value to a specified range.
Definition: mptrac.h:546
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1943
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_PBL, TURB_DZ_TROP, and TURB_DZ_STRAT define horizontal and vertical diffusivities (in units of m**2 s**-1) in the PBL, troposphere, and stratosphere, respectively.
  • Control parameter TURB_PBL_SCHEME activates an optional PBL-specific closure scheme. If a PBL scheme is active, the fixed-K module is only applied outside the PBL.
  • Apply the following settings to reproduce Stohl et al. (2005): TURB_DX_PBL = 50 TURB_DX_TROP = 50 TURB_DX_STRAT = 0 TURB_DZ_PBL = 0 TURB_DZ_TROP = 0 TURB_DZ_STRAT = 0.1 TURB_MESOX = 0.16 TURB_MESOZ = 0.16 TURB_PBL_SCHEME = 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_DZ_PBL = 0 TURB_DZ_TROP = 1.5 TURB_DZ_STRAT = 1.5 TURB_MESOX = 0 TURB_MESOZ = 0 TURB_PBL_SCHEME = 1
Author
Lars Hoffmann

Definition at line 4580 of file mptrac.c.

4586 {
4587
4588 /* Set timer... */
4589 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS");
4590
4591 /* Create random numbers... */
4592 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4593
4594 /* Loop over particles... */
4595 PARTICLE_LOOP(0, atm->np, 1,
4596 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4597
4598 /* Get PBL pressure... */
4599 double pbl;
4601 INTPOL_2D(pbl, 1);
4602
4603 /* Let optional PBL closure schemes handle turbulent diffusion inside the PBL. */
4604 if (ctl->turb_pbl_scheme > 0 && atm->p[ip] >= pbl)
4605 continue;
4606
4607 /* Get surface pressure... */
4608 double ps;
4609 INTPOL_2D(ps, 0);
4610
4611 /* Pressure at model top [hPa]. */
4612 const double ptop = met0->p[met0->np - 1];
4613
4614 /* Get weighting factors at current particle position... */
4615 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
4616 const double wtrop = tropo_weight(ctl, clim, atm, ip) * (1.0 - wpbl);
4617 const double wstrat = 1.0 - wpbl - wtrop;
4618
4619 /* Set diffusivities [m2/s]... */
4620 const double Kx =
4621 wpbl * ctl->turb_dx_pbl
4622 + wtrop * ctl->turb_dx_trop + wstrat * ctl->turb_dx_strat;
4623
4624 const double Kz =
4625 wpbl * ctl->turb_dz_pbl
4626 + wtrop * ctl->turb_dz_trop + wstrat * ctl->turb_dz_strat;
4627
4628 /* Set time step... */
4629 const double dt_abs = fabs(cache->dt[ip]);
4630
4631 /* Horizontal turbulent diffusion...
4632 Kx [m2/s], dt [s] => sigma_h [m]. */
4633 if (Kx > 0) {
4634 const double sigma_h = sqrt(2.0 * Kx * dt_abs);
4635
4636 atm->lon[ip] +=
4637 DX2COORD(met0, cache->rs[3 * ip] * sigma_h, atm->lat[ip]);
4638
4639 atm->lat[ip] += DY2COORD(met0, cache->rs[3 * ip + 1] * sigma_h);
4640 }
4641
4642 /* Vertical turbulent diffusion... */
4643 if (Kz > 0) {
4644
4645 /* Random displacement:
4646 Kz [m2/s], dt [s] => sigma_z [m], converted to [km]. */
4647 const double sigma_z = sqrt(2.0 * Kz * dt_abs) * 1e-3;
4648
4649 /* Save current pressure because pbl_weight() and tropo_weight()
4650 use atm->p[ip]. */
4651 const double p_save = atm->p[ip];
4652
4653 /* Estimate dKz/dz by centered finite difference.
4654 eps_km = 0.01 km = 10 m.
4655 Positive z is upward; therefore p_up < p_save and p_dn > p_save. */
4656 const double eps_km = 0.01;
4657 const double p_up = p_save + DZ2DP(eps_km, p_save);
4658 const double p_dn = p_save + DZ2DP(-eps_km, p_save);
4659
4660 /* Kz above... */
4661 atm->p[ip] = MAX(ptop, MIN(ps, p_up));
4662 const double wpbl_up = pbl_weight(ctl, atm, ip, pbl, ps);
4663 const double wtrop_up =
4664 tropo_weight(ctl, clim, atm, ip) * (1.0 - wpbl_up);
4665 const double wstrat_up = 1.0 - wpbl_up - wtrop_up;
4666
4667 const double Kz_up =
4668 wpbl_up * ctl->turb_dz_pbl
4669 + wtrop_up * ctl->turb_dz_trop + wstrat_up * ctl->turb_dz_strat;
4670
4671 /* Kz below... */
4672 atm->p[ip] = MAX(ptop, MIN(ps, p_dn));
4673 const double wpbl_dn = pbl_weight(ctl, atm, ip, pbl, ps);
4674 const double wtrop_dn =
4675 tropo_weight(ctl, clim, atm, ip) * (1.0 - wpbl_dn);
4676 const double wstrat_dn = 1.0 - wpbl_dn - wtrop_dn;
4677
4678 const double Kz_dn =
4679 wpbl_dn * ctl->turb_dz_pbl
4680 + wtrop_dn * ctl->turb_dz_trop + wstrat_dn * ctl->turb_dz_strat;
4681
4682 /* Restore current pressure... */
4683 atm->p[ip] = p_save;
4684
4685 /* Well-mixed drift:
4686 w_drift = dKz/dz + Kz * dlnrho/dz
4687
4688 Units:
4689 dKz_dz [m2/s] / [m] = [m/s]
4690 dlnrho_dz [1/m]
4691 Kz*dlnrho [m2/s] * [1/m] = [m/s]
4692 dz_drift [m/s] * [s] * 1e-3 = [km]
4693
4694 With exponential atmosphere rho ~ exp(-z/H0):
4695 dlnrho/dz = -1 / (1000 * H0)
4696 because H0 is in [km]. */
4697 const double dKz_dz = (Kz_up - Kz_dn) / (2.0 * eps_km * 1e3);
4698 const double dlnrho_dz = -1.0 / (1e3 * H0);
4699 const double w_drift = dKz_dz + Kz * dlnrho_dz;
4700 const double dz_drift = w_drift * dt_abs * 1e-3;
4701
4702 /* Total vertical displacement [km]. */
4703 const double dz_tot = cache->rs[3 * ip + 2] * sigma_z + dz_drift;
4704
4705 /* Update particle pressure... */
4706 double ptrial = p_save + DZ2DP(dz_tot, p_save);
4707
4708 /* Reflect at surface and model top.
4709 The transformation p -> pb^2 / p corresponds to reflection in
4710 logarithmic pressure / approximate height coordinates. Use repeated
4711 reflection for robustness in case a large random step crosses more
4712 than one boundary. */
4713 for (int iter = 0; iter < 10; iter++) {
4714 if (ptrial > ps)
4715 ptrial = ps * ps / ptrial;
4716 else if (ptrial < ptop)
4717 ptrial = ptop * ptop / ptrial;
4718 else
4719 break;
4720 }
4721
4722 /* Final safety clamp in case of an exceptionally large displacement... */
4723 atm->p[ip] = MAX(ptop, MIN(ps, ptrial));
4724 }
4725 }
4726}
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:8034
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:731
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2841
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2835
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2832
int turb_pbl_scheme
PBL turbulence scheme (0=none, 1=closure).
Definition: mptrac.h:2826
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2829
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2844
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2838
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 4730 of file mptrac.c.

4735 {
4736
4737 /* Set timer... */
4738 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS");
4739
4740 /* Check quantity flags... */
4741 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4742 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4743
4744 /* Loop over particles... */
4745 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4746
4747 /* Get surface pressure... */
4748 double ps;
4750 INTPOL_2D(ps, 1);
4751
4752 /* Check whether particle is above the surface layer... */
4753 if (atm->p[ip] < ps - ctl->dry_depo_dp)
4754 continue;
4755
4756 /* Set depth of surface layer... */
4757 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
4758
4759 /* Calculate sedimentation velocity for particles... */
4760 double v_dep;
4761 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
4762
4763 /* Get temperature... */
4764 double t;
4765 INTPOL_3D(t, 1);
4766
4767 /* Set deposition velocity... */
4768 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4769 atm->q[ctl->qnt_rhop][ip]);
4770 }
4771
4772 /* Use explicit sedimentation velocity for gases... */
4773 else
4774 v_dep = ctl->dry_depo_vdep;
4775
4776 /* Calculate loss of mass based on deposition velocity... */
4777 const double aux = exp(-cache->dt[ip] * v_dep / dz);
4778 if (ctl->qnt_m >= 0) {
4779 if (ctl->qnt_mloss_dry >= 0)
4780 atm->q[ctl->qnt_mloss_dry][ip]
4781 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4782 atm->q[ctl->qnt_m][ip] *= aux;
4783 if (ctl->qnt_loss_rate >= 0)
4784 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
4785 }
4786 if (ctl->qnt_vmr >= 0)
4787 atm->q[ctl->qnt_vmr][ip] *= aux;
4788 }
4789}
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:12182
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2324
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2321
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:3072
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2468
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:3075
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 4793 of file mptrac.c.

4799 {
4800
4801 if (ctl->met_coord_type != 0)
4802 ERRMSG("Only lat/lon grid supported");
4803
4804 /* Set timer... */
4805 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS");
4806
4807 /* Check quantity flags... */
4808 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4809 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4810
4811 /* Parameter of SO2 correction... */
4812 const double a = 3.12541941e-06;
4813 const double b = -5.72532259e-01;
4814 const double low = pow(1. / a, 1. / b);
4815
4816 /* Loop over particles... */
4817 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4818
4819 /* Check whether particle is inside cloud... */
4820 double lwc, rwc;
4822 INTPOL_3D(lwc, 1);
4823 INTPOL_3D(rwc, 0);
4824 if (!(lwc > 0 || rwc > 0))
4825 continue;
4826
4827 /* Get temperature... */
4828 double t;
4829 INTPOL_3D(t, 0);
4830
4831 /* Get molecular density... */
4832 const double M = MOLEC_DENS(atm->p[ip], t);
4833
4834 /* Reaction rate (Berglen et al., 2004)... */
4835 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
4836
4837 /* Henry constant of SO2... */
4838 const double H_SO2 =
4839 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
4840 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
4841
4842 /* Henry constant of H2O2... */
4843 const double H_h2o2 =
4844 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
4845
4846 /* Correction factor for high SO2 concentration
4847 (if qnt_Cx is defined, the correction is switched on)... */
4848 double cor = 1.0;
4849 if (ctl->qnt_Cx >= 0)
4850 cor = atm->q[ctl->qnt_Cx][ip] >
4851 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
4852
4853 const double h2o2 = H_h2o2
4854 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
4855 * M * cor * 1000. / AVO; /* unit: mol/L */
4856
4857 /* Volume water content in cloud [m^3 m^(-3)]... */
4858 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
4859 const double CWC = (lwc + rwc) * rho_air / 1e3;
4860
4861 /* Calculate exponential decay (Rolph et al., 1992)... */
4862 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
4863 const double aux = exp(-cache->dt[ip] * rate_coef);
4864 if (ctl->qnt_m >= 0) {
4865 if (ctl->qnt_mloss_h2o2 >= 0)
4866 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
4867 atm->q[ctl->qnt_m][ip] *= aux;
4868 if (ctl->qnt_loss_rate >= 0)
4869 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4870 }
4871 if (ctl->qnt_vmr >= 0)
4872 atm->q[ctl->qnt_vmr][ip] *= aux;
4873 }
4874}
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:250
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1284
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:320
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2459
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 4878 of file mptrac.c.

4883 {
4884
4885 double t;
4886
4887 /* Set timer... */
4888 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS");
4889
4890 /* Save pressure... */
4891 if (ctl->isosurf == 1) {
4892 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
4893 cache->iso_var[ip] = atm->p[ip];
4894 }
4895 }
4896
4897 /* Save density... */
4898 else if (ctl->isosurf == 2) {
4899 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4901 INTPOL_3D(t, 1);
4902 cache->iso_var[ip] = atm->p[ip] / t;
4903 }
4904 }
4905
4906 /* Save potential temperature... */
4907 else if (ctl->isosurf == 3) {
4908 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4910 INTPOL_3D(t, 1);
4911 cache->iso_var[ip] = THETA(atm->p[ip], t);
4912 }
4913 }
4914
4915 /* Read balloon pressure data... */
4916 else if (ctl->isosurf == 4) {
4917
4918 /* Write info... */
4919 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
4920
4921 /* Open file... */
4922 FILE *in;
4923 if (!(in = fopen(ctl->balloon, "r")))
4924 ERRMSG("Cannot open file!");
4925
4926 /* Read pressure time series... */
4927 char line[LEN];
4928 while (fgets(line, LEN, in))
4929 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
4930 &(cache->iso_ps[cache->iso_n])) == 2)
4931 if ((++cache->iso_n) > NP)
4932 ERRMSG("Too many data points!");
4933
4934 /* Check number of points... */
4935 if (cache->iso_n < 1)
4936 ERRMSG("Could not read any data!");
4937
4938 /* Close file... */
4939 fclose(in);
4940
4941 /* Update of cache data on device... */
4942 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4943 }
4944}
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:7694
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1914
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:359
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3405
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3408
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3402
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3399
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2810
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2807
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 4948 of file mptrac.c.

4953 {
4954
4955 /* Set timer... */
4956 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS");
4957
4958 /* Loop over particles... */
4959 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4960
4961 /* Init... */
4962 double t;
4964
4965 /* Restore pressure... */
4966 if (ctl->isosurf == 1)
4967 atm->p[ip] = cache->iso_var[ip];
4968
4969 /* Restore density... */
4970 else if (ctl->isosurf == 2) {
4971 INTPOL_3D(t, 1);
4972 atm->p[ip] = cache->iso_var[ip] * t;
4973 }
4974
4975 /* Restore potential temperature... */
4976 else if (ctl->isosurf == 3) {
4977 INTPOL_3D(t, 1);
4978 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
4979 }
4980
4981 /* Interpolate pressure... */
4982 else if (ctl->isosurf == 4) {
4983 if (atm->time[ip] <= cache->iso_ts[0])
4984 atm->p[ip] = cache->iso_ps[0];
4985 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
4986 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
4987 else {
4988 const int idx =
4989 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
4990 atm->p[ip] =
4991 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
4992 cache->iso_ps[idx + 1], atm->time[ip]);
4993 }
4994 }
4995 }
4996}
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 5054 of file mptrac.c.

5060 {
5061
5062 /* Set timer... */
5063 SELECT_TIMER("MODULE_METEO", "PHYSICS");
5064
5065 /* Check quantity flags... */
5066 if (ctl->qnt_tsts >= 0)
5067 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
5068 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
5069
5070 /* Loop over particles... */
5071 PARTICLE_LOOP(0, atm->np, 0,
5072 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5073
5074 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
5075 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
5076 o3, lwc, rwc, iwc, swc, cc, z, zt;
5077
5078 /* Interpolate meteo data... */
5080 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
5081
5082 /* Set quantities... */
5083 SET_ATM(qnt_ps, ps);
5084 SET_ATM(qnt_ts, ts);
5085 SET_ATM(qnt_zs, zs);
5086 SET_ATM(qnt_us, us);
5087 SET_ATM(qnt_vs, vs);
5088 SET_ATM(qnt_ess, ess);
5089 SET_ATM(qnt_nss, nss);
5090 SET_ATM(qnt_shf, shf);
5091 SET_ATM(qnt_lsm, lsm);
5092 SET_ATM(qnt_sst, sst);
5093 SET_ATM(qnt_pbl, pbl);
5094 SET_ATM(qnt_pt, pt);
5095 SET_ATM(qnt_tt, tt);
5096 SET_ATM(qnt_zt, zt);
5097 SET_ATM(qnt_h2ot, h2ot);
5098 SET_ATM(qnt_zg, z);
5099 SET_ATM(qnt_p, atm->p[ip]);
5100 SET_ATM(qnt_t, t);
5101 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
5102 SET_ATM(qnt_u, u);
5103 SET_ATM(qnt_v, v);
5104 SET_ATM(qnt_w, w);
5105 SET_ATM(qnt_h2o, h2o);
5106 SET_ATM(qnt_o3, o3);
5107 SET_ATM(qnt_lwc, lwc);
5108 SET_ATM(qnt_rwc, rwc);
5109 SET_ATM(qnt_iwc, iwc);
5110 SET_ATM(qnt_swc, swc);
5111 SET_ATM(qnt_cc, cc);
5112 SET_ATM(qnt_pct, pct);
5113 SET_ATM(qnt_pcb, pcb);
5114 SET_ATM(qnt_cl, cl);
5115 SET_ATM(qnt_plcl, plcl);
5116 SET_ATM(qnt_plfc, plfc);
5117 SET_ATM(qnt_pel, pel);
5118 SET_ATM(qnt_cape, cape);
5119 SET_ATM(qnt_cin, cin);
5120 SET_ATM(qnt_o3c, o3c);
5121 const double lat_ref =
5122 ctl->met_coord_type == 0 ? atm->lat[ip] : ctl->met_utm_ref_lat;
5123 SET_ATM(qnt_hno3,
5124 clim_zm(&clim->hno3, atm->time[ip], lat_ref, atm->p[ip]));
5125 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
5126 atm->lon[ip], atm->lat[ip], atm->p[ip]));
5127 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
5128 lat_ref, atm->p[ip]));
5129 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip], lat_ref, atm->p[ip]));
5130 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip], lat_ref, atm->p[ip]));
5131 SET_ATM(qnt_vh, sqrt(u * u + v * v));
5132 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
5133 SET_ATM(qnt_psat, PSAT(t));
5134 SET_ATM(qnt_psice, PSICE(t));
5135 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
5136 SET_ATM(qnt_sh, SH(h2o));
5137 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
5138 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
5139 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
5140 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
5141 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
5142 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
5143 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
5144 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
5145 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
5146 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
5147 SET_ATM(qnt_pv, pv);
5148 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
5149 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
5150 SET_ATM(qnt_tnat,
5151 nat_temperature(atm->p[ip], h2o,
5152 clim_zm(&clim->hno3, atm->time[ip],
5153 atm->lat[ip], atm->p[ip])));
5154 SET_ATM(qnt_tsts,
5155 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
5156 }
5157}
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:8010
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:3324
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1649
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1622
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1890
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1726
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:1068
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1696
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1865
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1598
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3557
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2537
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2510
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2531
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2504
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2534
Here is the call graph for this function:

◆ module_mixing()

void module_mixing ( const ctl_t ctl,
const clim_t clim,
atm_t atm,
const double  t 
)

Update atmospheric properties through interparcel mixing.

This function updates atmospheric properties by performing interparcel mixing based on the given meteorological and climatological data. It calculates the indices of grid boxes and performs mixing for various quantities such as mass, volume mixing ratio, and other chemical species concentrations.

Parameters
ctlPointer to the control structure containing simulation parameters.
climPointer to the climate data structure containing climatological data.
atmPointer to the atmospheric data structure containing particle information.
tTime at which mixing is performed.
Author
Mingzhao Liu
Lars Hoffmann

Definition at line 5161 of file mptrac.c.

5165 {
5166
5167 /* Set timer... */
5168 SELECT_TIMER("MODULE_MIXING", "PHYSICS");
5169
5170 /* Allocate... */
5171 const int np = atm->np;
5172 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
5173 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
5174 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
5175
5176 /* Set grid box size... */
5177 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
5178 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
5179 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
5180
5181 /* Set time interval... */
5182 const double t0 = t - 0.5 * ctl->dt_mod;
5183 const double t1 = t + 0.5 * ctl->dt_mod;
5184
5185 /* Get indices... */
5186#ifdef _OPENACC
5187#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
5188#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
5189#pragma acc parallel loop independent gang vector
5190#else
5191#pragma omp parallel for default(shared)
5192#endif
5193 for (int ip = 0; ip < np; ip++) {
5194 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
5195 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
5196 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
5197 if (atm->time[ip] < t0 || atm->time[ip] > t1
5198 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
5199 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
5200 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
5201 izs[ip] = -1;
5202 }
5203
5204 /* Calculate interparcel mixing... */
5205 const int use_ensemble = (ctl->nens > 0);
5206
5207 const int quantities[] = {
5208 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
5209 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
5210 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
5211 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
5212 ctl->qnt_Csf6, ctl->qnt_aoa, ctl->qnt_Arn222, ctl->qnt_Apb210,
5213 ctl->qnt_Abe7, ctl->qnt_Acs137, ctl->qnt_Ai131, ctl->qnt_Axe133
5214 };
5215 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
5216
5217 for (int i = 0; i < n_qnt; i++)
5218 if (quantities[i] >= 0)
5219 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
5220 use_ensemble);
5221
5222 /* Free... */
5223#ifdef _OPENACC
5224#pragma acc exit data delete(ixs,iys,izs)
5225#endif
5226 free(ixs);
5227 free(iys);
5228 free(izs);
5229}
void module_mixing_help(const ctl_t *ctl, const clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, const int qnt_idx, const int use_ensemble)
Perform subgrid-scale interparcel mixing of a given quantity.
Definition: mptrac.c:5233
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2552
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2973
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2970
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2564
int qnt_Acs137
Quantity array index for radioactive activity of Cs-137.
Definition: mptrac.h:2597
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2967
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2549
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2982
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2555
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2985
int qnt_Ai131
Quantity array index for radioactive activity of I-131.
Definition: mptrac.h:2600
int qnt_Apb210
Quantity array index for radioactive activity of Pb-210.
Definition: mptrac.h:2591
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2558
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2964
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2976
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2988
int qnt_Axe133
Quantity array index for radioactive activity of Xe-133.
Definition: mptrac.h:2603
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2567
int qnt_Abe7
Quantity array index for radioactive activity of Be-7.
Definition: mptrac.h:2594
int qnt_Arn222
Quantity array index for radioactive activity of Rn-222.
Definition: mptrac.h:2588
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2561
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2979
Here is the call graph for this function:

◆ module_mixing_help()

void module_mixing_help ( const ctl_t ctl,
const clim_t clim,
atm_t atm,
const int *  ixs,
const int *  iys,
const int *  izs,
const int  qnt_idx,
const int  use_ensemble 
)

Perform subgrid-scale interparcel mixing of a given quantity.

This function computes the average of a specified quantity within each subgrid box (and optionally for each ensemble member) and applies a mixing adjustment to particle values based on the computed local mean.

The mixing accounts for differences in tropopause and stratosphere mixing via a weighted parameterization. It supports both ensemble and non-ensemble modes using the use_ensemble flag.

Parameters
[in]ctlPointer to control/configuration structure.
[in]climPointer to climatological data structure.
[in,out]atmPointer to atmospheric state (includes particles).
[in]ixsArray of x-grid indices for each particle.
[in]iysArray of y-grid indices for each particle.
[in]izsArray of z-grid indices for each particle (-1 for invalid).
[in]qnt_idxIndex of the quantity in atm->q to be mixed.
[in]use_ensembleFlag indicating whether to use ensemble-aware logic (0 = no, 1 = yes).
Note
Particles with izs[ip] < 0 are excluded from mixing.
Uses OpenACC or OpenMP for parallelism depending on compilation options.
Requires ctl->qnt_ens to be valid if use_ensemble is true.
Author
Mingzhao Liu
Lars Hoffmann

Definition at line 5233 of file mptrac.c.

5241 {
5242
5243 const int np = atm->np;
5244 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
5245 const int nens = use_ensemble ? ctl->nens : 1;
5246 const int total_grid = ngrid * nens;
5247
5248 double *restrict const cmean =
5249 (double *) malloc((size_t) total_grid * sizeof(double));
5250 int *restrict const count =
5251 (int *) malloc((size_t) total_grid * sizeof(int));
5252
5253 /* Init... */
5254#ifdef _OPENACC
5255#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
5256#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
5257#pragma acc parallel loop independent gang vector
5258#else
5259#ifdef __NVCOMPILER
5260#pragma novector
5261#endif
5262#pragma omp parallel for
5263#endif
5264 for (int i = 0; i < total_grid; i++) {
5265 count[i] = 0;
5266 cmean[i] = 0.0;
5267 }
5268
5269 /* Loop over particles... */
5270#ifdef _OPENACC
5271#pragma acc parallel loop independent gang vector
5272#endif
5273 for (int ip = 0; ip < np; ip++)
5274 if (izs[ip] >= 0) {
5275 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5276 const int idx =
5277 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5278 ctl->mixing_nz);
5279#ifdef _OPENACC
5280#pragma acc atomic update
5281#endif
5282 cmean[idx] += atm->q[qnt_idx][ip];
5283#ifdef _OPENACC
5284#pragma acc atomic update
5285#endif
5286 count[idx]++;
5287 }
5288
5289 /* Compute means... */
5290#ifdef _OPENACC
5291#pragma acc parallel loop independent gang vector
5292#else
5293#ifdef __NVCOMPILER
5294#pragma novector
5295#endif
5296#pragma omp parallel for
5297#endif
5298 for (int i = 0; i < total_grid; i++)
5299 if (count[i] > 0)
5300 cmean[i] /= count[i];
5301
5302 /* Interparcel mixing... */
5303#ifdef _OPENACC
5304#pragma acc parallel loop independent gang vector
5305#else
5306#pragma omp parallel for
5307#endif
5308 for (int ip = 0; ip < np; ip++) {
5309 if (izs[ip] >= 0) {
5310 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5311
5312 double mixparam = 1.0;
5313 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
5314 const double w = tropo_weight(ctl, clim, atm, ip);
5315 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
5316 }
5317
5318 const int idx =
5319 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5320 ctl->mixing_nz);
5321 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
5322 }
5323 }
5324
5325 /* Free... */
5326#ifdef _OPENACC
5327#pragma acc exit data delete(cmean,count)
5328#endif
5329 free(cmean);
5330 free(count);
5331}
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2958
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2961
Here is the call graph for this function:

◆ module_oh_chem()

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

Perform hydroxyl chemistry calculations for atmospheric particles.

This function calculates the OH chemistry for each atmospheric particle based on the specified reaction mechanism and updates the particle quantities accordingly. The OH chemistry includes bimolecular and termolecular reactions, and the reaction rates are calculated based on the provided climatological data and atmospheric conditions. The function supports both mass and volume mixing ratio quantities for the particles.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climate data structure containing climatological data.
met0Pointer to the first meteorological data structure.
met1Pointer to the second meteorological data structure.
atmPointer to the atmospheric data structure containing particle information.
Note
The function assumes that the necessary meteorological and climatological data structures have been initialized and are accessible via the pointers met0, met1, and clim, respectively.
The reaction rates are calculated based on the provided reaction mechanism and atmospheric conditions, including temperature, pressure, and the concentrations of relevant species.
The function updates the particle quantities based on the calculated reaction rates and the specified time steps. The update can include both mass and volume mixing ratio quantities, as determined by the control structure (ctl).
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 5335 of file mptrac.c.

5341 {
5342
5343 /* Set timer... */
5344 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS");
5345
5346 /* Check quantity flags... */
5347 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5348 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5349
5350 /* Parameter of SO2 correction... */
5351 const double a = 4.71572206e-08;
5352 const double b = -8.28782867e-01;
5353 const double low = pow(1. / a, 1. / b);
5354
5355 /* Loop over particles... */
5356 PARTICLE_LOOP(0, atm->np, 1,
5357 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5358
5359 /* Get temperature... */
5360 double t;
5362 INTPOL_3D(t, 1);
5363
5364 /* Calculate molecular density... */
5365 const double M = MOLEC_DENS(atm->p[ip], t);
5366
5367 /* Use constant reaction rate... */
5368 double k = NAN;
5369 if (ctl->oh_chem_reaction == 1)
5370 k = ctl->oh_chem[0];
5371
5372 /* Calculate bimolecular reaction rate... */
5373 else if (ctl->oh_chem_reaction == 2)
5374 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
5375
5376 /* Calculate termolecular reaction rate... */
5377 if (ctl->oh_chem_reaction == 3) {
5378
5379 /* Calculate rate coefficient for X + OH + M -> XOH + M
5380 (JPL Publication 19-05) ... */
5381 const double k0 =
5382 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
5383 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
5384 const double ki =
5385 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
5386 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
5387 const double c = log10(k0 * M / ki);
5388 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
5389 }
5390
5391 /* Correction factor for high SO2 concentration
5392 (if qnt_Cx is defined, the correction is switched on)... */
5393 double cor = 1;
5394 if (ctl->qnt_Cx >= 0)
5395 cor =
5396 atm->q[ctl->qnt_Cx][ip] >
5397 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
5398
5399 /* Calculate exponential decay... */
5400 const double rate_coef =
5401 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
5402 atm->lat[ip], atm->p[ip]) * M * cor;
5403 const double aux = exp(-cache->dt[ip] * rate_coef);
5404 if (ctl->qnt_m >= 0) {
5405 if (ctl->qnt_mloss_oh >= 0)
5406 atm->q[ctl->qnt_mloss_oh][ip]
5407 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5408 atm->q[ctl->qnt_m][ip] *= aux;
5409 if (ctl->qnt_loss_rate >= 0)
5410 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
5411 }
5412 if (ctl->qnt_vmr >= 0)
5413 atm->q[ctl->qnt_vmr][ip] *= aux;
5414 }
5415}
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:3021
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:3018
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2456
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 5419 of file mptrac.c.

5423 {
5424
5425 /* Set timer... */
5426 SELECT_TIMER("MODULE_POSITION", "PHYSICS");
5427
5428 /* Loop over particles... */
5429 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
5430
5431 /* Init... */
5432 double ps;
5434
5435 if (met0->coord_type == 0) {
5436 /* Calculate modulo... */
5437 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
5438 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
5439
5440 /* Check latitude... */
5441 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
5442 if (atm->lat[ip] > 90) {
5443 atm->lat[ip] = 180 - atm->lat[ip];
5444 atm->lon[ip] += 180;
5445 }
5446 if (atm->lat[ip] < -90) {
5447 atm->lat[ip] = -180 - atm->lat[ip];
5448 atm->lon[ip] += 180;
5449 }
5450 }
5451
5452 /* Check longitude... */
5453 while (atm->lon[ip] < -180)
5454 atm->lon[ip] += 360;
5455 while (atm->lon[ip] >= 180)
5456 atm->lon[ip] -= 360;
5457 } else {
5458 intpol_check_cartesian(met0->lon, met0->nx, met0->lat, met0->ny,
5459 atm->lon[ip], atm->lat[ip], &atm->lon[ip],
5460 &atm->lat[ip]);
5461 }
5462
5463 /* Check pressure... */
5464 const double ptop = met0->p[met0->np - 1];
5465 if (atm->p[ip] < ptop) {
5466 atm->p[ip] = ptop * ptop / atm->p[ip];
5467 } else if (atm->p[ip] > 300.) {
5468 INTPOL_2D(ps, 0);
5469 if (atm->p[ip] > ps)
5470 atm->p[ip] = ps * ps / atm->p[ip];
5471 }
5472 }
5473}
Here is the call graph for this function:

◆ module_radio_decay()

void module_radio_decay ( const ctl_t ctl,
const cache_t cache,
atm_t atm 
)

Apply radioactive decay to atmospheric tracer species.

This routine updates the concentrations of radioactive tracers carried by atmospheric particles by applying exponential decay over the current particle timestep. The decay constants are derived from the half-lives of the respective isotopes.

Implemented isotopes:

  • Rn-222
  • Pb-210
  • Be-7
  • Cs-137
  • I-131
  • Xe-133

For each particle, the tracer mixing ratios are reduced according to \( q(t+\Delta t) = q(t) \exp(-\lambda \Delta t) \), where \(\lambda\) is the decay constant and \(\Delta t\) is the particle timestep.

Additionally, the decay of Rn-222 contributes to the production of Pb-210 via a simplified parent–daughter relationship.

The update is performed only if the corresponding tracer index in the control structure is non-negative.

Parameters
[in]ctlControl structure containing tracer indices.
[in]cacheCache structure providing particle timesteps.
[in,out]atmAtmospheric state containing particle tracer fields that are updated in place.
Author
Lars Hoffmann

Definition at line 5477 of file mptrac.c.

5480 {
5481
5482 /* Set timer... */
5483 SELECT_TIMER("MODULE_RADIO_DECAY", "PHYSICS");
5484
5485 /* Set decay constants of radioactive species [s^-1]... */
5486 const double lambda_rn222 = log(2.0) / (3.8235 * 86400.0);
5487 const double lambda_pb210 = log(2.0) / (22.3 * 365.25 * 86400.0);
5488 const double lambda_be7 = log(2.0) / (53.22 * 86400.0);
5489 const double lambda_cs137 = log(2.0) / (30.05 * 365.25 * 86400.0);
5490 const double lambda_i131 = log(2.0) / (8.02 * 86400.0);
5491 const double lambda_xe133 = log(2.0) / (5.2474 * 86400.0);
5492
5493 /* Loop over particles... */
5494 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,atm)") {
5495
5496 /* Set timestep... */
5497 const double dt = cache->dt[ip];
5498
5499 /* Loss for Pb-210... */
5500 if (ctl->qnt_Apb210 >= 0)
5501 atm->q[ctl->qnt_Apb210][ip] *= exp(-dt * lambda_pb210);
5502
5503 /* Loss for Rn-222... */
5504 if (ctl->qnt_Arn222 >= 0) {
5505 const double old = atm->q[ctl->qnt_Arn222][ip];
5506 const double aux = exp(-dt * lambda_rn222);
5507 const double lost = old * (1.0 - aux);
5508 atm->q[ctl->qnt_Arn222][ip] = old * aux;
5509
5510 /* Parent-daughter process for Pb-210... */
5511 if (ctl->qnt_Apb210 >= 0)
5512 atm->q[ctl->qnt_Apb210][ip] += lost * lambda_pb210 / lambda_rn222;
5513 }
5514
5515 /* Loss for Be-7... */
5516 if (ctl->qnt_Abe7 >= 0)
5517 atm->q[ctl->qnt_Abe7][ip] *= exp(-dt * lambda_be7);
5518
5519 /* Loss for Cs-137... */
5520 if (ctl->qnt_Acs137 >= 0)
5521 atm->q[ctl->qnt_Acs137][ip] *= exp(-dt * lambda_cs137);
5522
5523 /* Loss for I-131... */
5524 if (ctl->qnt_Ai131 >= 0)
5525 atm->q[ctl->qnt_Ai131][ip] *= exp(-dt * lambda_i131);
5526
5527 /* Loss for Xe-133... */
5528 if (ctl->qnt_Axe133 >= 0)
5529 atm->q[ctl->qnt_Axe133][ip] *= exp(-dt * lambda_xe133);
5530 }
5531}

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

5536 {
5537
5538 /* Initialize GSL random number generators... */
5539 gsl_rng_env_setup();
5540 if (omp_get_max_threads() > NTHREADS)
5541 ERRMSG("Too many threads!");
5542 for (int i = 0; i < NTHREADS; i++) {
5543 rng[i] = gsl_rng_alloc(gsl_rng_default);
5544 gsl_rng_set(rng[i], gsl_rng_default_seed
5545 + (long unsigned) (ntask * NTHREADS + i));
5546 }
5547
5548 /* Initialize cuRAND random number generators... */
5549#ifdef CURAND
5550 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
5551 CURAND_STATUS_SUCCESS)
5552 ERRMSG("Cannot create random number generator!");
5553 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
5554 CURAND_STATUS_SUCCESS)
5555 ERRMSG("Cannot set seed for random number generator!");
5556 if (curandSetStream
5557 (rng_curand,
5558 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
5559 CURAND_STATUS_SUCCESS)
5560 ERRMSG("Cannot set stream for random number generator!");
5561#endif
5562}
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:384

◆ module_rng()

void module_rng ( const ctl_t ctl,
double *  rs,
const size_t  n,
const int  method 
)

Generate random numbers using various methods and distributions.

This function generates random numbers using different methods and distributions based on the specified method and random number generator type. It supports uniform and normal distributions and can utilize GSL, Squares (Widynski, 2022), or cuRAND random number generators.

Parameters
ctlPointer to the control structure containing parameters and settings.
rsPointer to the array where the generated random numbers will be stored.
nThe number of random numbers to generate.
methodThe method for generating random numbers:
  • 0: Uniform distribution
  • 1: Normal distribution
Note
The function selects the appropriate random number generator based on the specified method and the random number generator type defined in the control structure (ctl->rng_type).
For uniform distribution, the generated random numbers are in the range [0, 1).
For normal distribution, the Box-Muller transform is used to generate pairs of random numbers and transform them into a normal distribution.
If cuRAND is not available (CURAND macro not defined), the function returns an error message.
Author
Lars Hoffmann

Definition at line 5566 of file mptrac.c.

5570 {
5571
5572 /* Use GSL random number generators... */
5573 if (ctl->rng_type == 0) {
5574
5575 /* Uniform distribution... */
5576 if (method == 0) {
5577#pragma omp parallel for default(shared)
5578 for (size_t i = 0; i < n; ++i)
5579 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
5580 }
5581
5582 /* Normal distribution... */
5583 else if (method == 1) {
5584#pragma omp parallel for default(shared)
5585 for (size_t i = 0; i < n; ++i)
5586 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
5587 }
5588
5589 /* Update of random numbers on device... */
5590#ifdef _OPENACC
5591 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
5592#pragma acc update device(rs[:n])
5593#endif
5594 }
5595
5596 /* Use Squares random number generator (Widynski, 2022)... */
5597 else if (ctl->rng_type == 1) {
5598
5599 /* Set key (don't change this!)... */
5600 const uint64_t key = 0xc8e4fd154ce32f6d;
5601
5602 /* Uniform distribution... */
5603#ifdef _OPENACC
5604#pragma acc data present(rs)
5605#pragma acc parallel loop independent gang vector
5606#else
5607#pragma omp parallel for default(shared)
5608#endif
5609 for (size_t i = 0; i < n + 1; ++i) {
5610 uint64_t r, t, x, y, z;
5611 y = x = (rng_ctr + i) * key;
5612 z = y + key;
5613 x = x * x + y;
5614 x = (x >> 32) | (x << 32);
5615 x = x * x + z;
5616 x = (x >> 32) | (x << 32);
5617 x = x * x + y;
5618 x = (x >> 32) | (x << 32);
5619 t = x = x * x + z;
5620 x = (x >> 32) | (x << 32);
5621 r = t ^ ((x * x + y) >> 32);
5622 rs[i] = (double) r / (double) UINT64_MAX;
5623 }
5624 rng_ctr += n + 1;
5625
5626 /* Normal distribution... */
5627 if (method == 1) {
5628#ifdef _OPENACC
5629#pragma acc parallel loop independent gang vector
5630#else
5631#pragma omp parallel for default(shared)
5632#endif
5633 for (size_t i = 0; i < n; i += 2) {
5634 const double r = sqrt(-2.0 * log(rs[i]));
5635 const double phi = 2.0 * M_PI * rs[i + 1];
5636 rs[i] = r * cosf((float) phi);
5637 rs[i + 1] = r * sinf((float) phi);
5638 }
5639 }
5640 }
5641
5642 /* Use cuRAND random number generators... */
5643 else if (ctl->rng_type == 2) {
5644#ifdef CURAND
5645#pragma acc host_data use_device(rs)
5646 {
5647
5648 /* Uniform distribution... */
5649 if (method == 0) {
5650 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
5651 CURAND_STATUS_SUCCESS)
5652 ERRMSG("Cannot create random numbers!");
5653 }
5654
5655 /* Normal distribution... */
5656 else if (method == 1) {
5657 if (curandGenerateNormalDouble
5658 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
5659 1.0) != CURAND_STATUS_SUCCESS)
5660 ERRMSG("Cannot create random numbers!");
5661 }
5662 }
5663#else
5664 ERRMSG("MPTRAC was compiled without cuRAND!");
5665#endif
5666 }
5667}
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2820

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

5676 {
5677
5678 /* Set timer... */
5679 SELECT_TIMER("MODULE_SEDI", "PHYSICS")
5680 /* Loop over particles... */
5681 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5682
5683 /* Get temperature... */
5684 double t;
5686 INTPOL_3D(t, 1);
5687
5688 /* Sedimentation velocity... */
5689 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
5690 atm->q[ctl->qnt_rhop][ip]);
5691
5692 /* Calculate pressure change... */
5693 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
5694 }
5695}
Here is the call graph for this function:

◆ module_sort()

void module_sort ( const ctl_t ctl,
const met_t met0,
atm_t atm 
)

Sort particles according to box index.

This function sorts particles within the atmosphere data structure based on their geographical coordinates (longitude and latitude) and pressure level. It allocates temporary arrays to store indices and auxiliary data for sorting, then performs the sorting operation. After sorting, it updates the order of particles in the atmosphere data structure.

Parameters
ctlPointer to the control structure containing parameters and settings.
met0Pointer to the meteorological data at the current time step.
atmPointer to the atmospheric data containing particle information.
Note
The function utilizes the locate_reg and locate_irr functions to determine the appropriate index for sorting particles based on their longitude, latitude, and pressure level.
Particle sorting is performed using either the Thrust library (if compiled with Thrust support) or a custom sorting algorithm. If compiled without Thrust support, an error message is displayed.
After sorting, the function updates the order of particle-related data arrays in the atmosphere data structure to maintain consistency.
Author
Lars Hoffmann

Definition at line 5699 of file mptrac.c.

5702 {
5703
5704 /* Set timer... */
5705 SELECT_TIMER("MODULE_SORT", "PHYSICS");
5706
5707 /* Allocate... */
5708 const int np = atm->np;
5709 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
5710 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
5711 if (a == NULL || p == NULL)
5712 ERRMSG("Out of memory!");
5713
5714#ifdef _OPENACC
5715#pragma acc enter data create(a[0:np],p[0:np])
5716#pragma acc data present(ctl,met0,atm,a,p)
5717#endif
5718
5719 /* Get box index... */
5720#ifdef _OPENACC
5721#pragma acc parallel loop independent gang vector
5722#else
5723#pragma omp parallel for default(shared)
5724#endif
5725 for (int ip = 0; ip < np; ip++) {
5726 a[ip] =
5727 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
5728 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
5729 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
5730 p[ip] = ip;
5731 }
5732
5733 /* Sorting... */
5734#ifdef THRUST
5735#ifdef _OPENACC
5736#pragma acc host_data use_device(a,p)
5737#endif
5738 thrustSortWrapper(a, np, p);
5739#else
5740 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
5741 if (perm_sz == NULL)
5742 ERRMSG("Out of memory!");
5743#ifdef _OPENACC
5744#pragma acc update self(a[0:np])
5745#endif
5746 gsl_sort_index(perm_sz, a, 1, (size_t) np);
5747 for (int ip = 0; ip < np; ++ip)
5748 p[ip] = (int) perm_sz[ip];
5749 free(perm_sz);
5750#ifdef _OPENACC
5751#pragma acc update device(p[0:np])
5752#endif
5753#endif
5754
5755 /* Sort data... */
5756 module_sort_help(atm->time, p, np);
5757 module_sort_help(atm->p, p, np);
5758 module_sort_help(atm->lon, p, np);
5759 module_sort_help(atm->lat, p, np);
5760 for (int iq = 0; iq < ctl->nq; iq++)
5761 module_sort_help(atm->q[iq], p, np);
5762
5763 /* Free... */
5764#ifdef _OPENACC
5765#pragma acc exit data delete(a,p)
5766#endif
5767 free(a);
5768 free(p);
5769}
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:5773
int nq
Number of quantities.
Definition: mptrac.h:2291
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 5773 of file mptrac.c.

5776 {
5777
5778 /* Allocate... */
5779 double *restrict const help =
5780 (double *) malloc((size_t) np * sizeof(double));
5781 if (help == NULL)
5782 ERRMSG("Out of memory!");
5783
5784 /* Reordering of array... */
5785#ifdef _OPENACC
5786#pragma acc enter data create(help[0:np])
5787#pragma acc data present(a,p,help)
5788#pragma acc parallel loop independent gang vector
5789#else
5790#pragma omp parallel for default(shared)
5791#endif
5792 for (int ip = 0; ip < np; ip++)
5793 help[ip] = a[p[ip]];
5794#ifdef _OPENACC
5795#pragma acc parallel loop independent gang vector
5796#else
5797#pragma omp parallel for default(shared)
5798#endif
5799 for (int ip = 0; ip < np; ip++)
5800 a[ip] = help[ip];
5801
5802 /* Free... */
5803#ifdef _OPENACC
5804#pragma acc exit data delete(help)
5805#endif
5806 free(help);
5807}

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

5816 {
5817
5818 /* Set timer... */
5819 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS");
5820
5821 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
5822 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
5823
5824 const int local =
5825 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
5826
5827 /* Loop over particles... */
5828 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
5829
5830 /* Set time step for each air parcel... */
5831 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
5832 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
5833 && ctl->direction * (atm->time[ip] - t) < 0))
5834 cache->dt[ip] = t - atm->time[ip];
5835 else
5836 cache->dt[ip] = 0.0;
5837
5838 /* Check horizontal boundaries of local meteo data... */
5839#ifndef DD
5840 int dd = 1;
5841#else
5842 int dd = 0;
5843#endif
5844 if (dd) {
5845 if (local && (atm->lon[ip] <= met0->lon[0]
5846 || atm->lon[ip] >= met0->lon[met0->nx - 1]
5847 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
5848 cache->dt[ip] = 0.0;
5849 } else {
5850 if ((int) atm->q[ctl->qnt_current_subdomain][ip] == -1)
5851 cache->dt[ip] = 0;
5852 }
5853 }
5854}
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2612
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2618
int qnt_current_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2606
double t_start
Start time of simulation [s].
Definition: mptrac.h:2615

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

5860 {
5861
5862 /* Set timer... */
5863 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS");
5864
5865 /* Set start time... */
5866 if (ctl->direction == 1) {
5867 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
5868 if (ctl->t_stop > 1e99)
5869 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
5870 } else {
5871 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
5872 if (ctl->t_stop > 1e99)
5873 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
5874 }
5875
5876 /* Check time interval... */
5877 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
5878 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
5879
5880 /* Round start time... */
5881 if (ctl->direction == 1)
5882 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
5883 else
5884 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
5885}

◆ module_tracer_chem()

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

Simulate chemical reactions involving long-lived atmospheric tracers.

This function simulates chemical reactions involving atmospheric tracers, such as CFC-10, CFC-11, CFC-12, and N2O. It calculates the change in tracer concentrations over time based on reaction rates and environmental factors such as temperature, ozone concentration, solar zenith angle, and O(1D) volume mixing ratio.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climatological data structure.
met0Pointer to the first meteorological data structure.
met1Pointer to the second meteorological data structure.
atmPointer to the atmospheric data structure containing particle information.
Note
The function assumes that the necessary control structure (ctl), climatological data structure (clim), meteorological data structures (met0, met1), and atmospheric data structure (atm) have been initialized and are accessible.
Chemical reactions involving CFC-10, CFC-11, CFC-12, and N2O are simulated for each particle in the atmospheric data structure.
The function calculates reaction rates based on temperature, solar zenith angle, total column ozone, and the volume mixing ratio of O(1D).
The exponential decay of tracer concentrations due to chemical reactions is calculated using reaction rate coefficients and the time step (dt) for each particle.
If the particle has a quantity flag for the tracer species (e.g., ctl->qnt_Cccl4, ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o), the function updates the concentration of the tracer based on the exponential decay.
Author
Mingzhao Liu
Lars Hoffmann

Definition at line 5889 of file mptrac.c.

5895 {
5896
5897 if (ctl->met_coord_type != 0)
5898 ERRMSG("Only lat/lon grid supported");
5899
5900 /* Set timer... */
5901 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS");
5902
5903 /* Loop over particles... */
5904 PARTICLE_LOOP(0, atm->np, 1,
5905 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5906
5907 /* Get temperature... */
5908 double t;
5910 INTPOL_3D(t, 1);
5911
5912 /* Get molecular density... */
5913 const double M = MOLEC_DENS(atm->p[ip], t);
5914
5915 /* Get total column ozone... */
5916 double o3c;
5917 INTPOL_2D(o3c, 1);
5918
5919 /* Get solar zenith angle... */
5920 const double sza =
5921 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
5922
5923 /* Get O(1D) volume mixing ratio... */
5924 const double o1d =
5925 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
5926
5927 /* Reactions for CFC-10... */
5928 if (ctl->qnt_Cccl4 >= 0) {
5929 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
5930 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
5931 atm->p[ip], sza, o3c);
5932 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5933 }
5934
5935 /* Reactions for CFC-11... */
5936 if (ctl->qnt_Cccl3f >= 0) {
5937 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
5938 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
5939 atm->p[ip], sza, o3c);
5940 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5941 }
5942
5943 /* Reactions for CFC-12... */
5944 if (ctl->qnt_Cccl2f2 >= 0) {
5945 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
5946 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
5947 atm->p[ip], sza, o3c);
5948 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5949 }
5950
5951 /* Reactions for N2O... */
5952 if (ctl->qnt_Cn2o >= 0) {
5953 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
5954 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
5955 atm->p[ip], sza, o3c);
5956 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5957 }
5958 }
5959}
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:156
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:524
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3458
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3455
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3449
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3452
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3554
Here is the call graph for this function:

◆ module_wet_depo()

void module_wet_depo ( const ctl_t ctl,
const cache_t cache,
met_t met0,
met_t met1,
atm_t atm 
)

Perform wet deposition calculations for air parcels.

This function calculates the wet deposition process for each air parcel based on provided atmospheric and meteorological data. It estimates the precipitation rate and scavenging coefficients for particles and gases inside and below cloud layers. The scavenging coefficients are used to calculate the exponential decay of mass or volume mixing ratio over time due to wet deposition.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the initial meteorological data structure.
met1Pointer to the updated meteorological data structure.
atmPointer to the atmospheric data structure containing air parcel information.
Note
The function calculates the wet deposition process for particles and gases based on precipitation rate and scavenging coefficients inside and below cloud layers.
It estimates the exponential decay of mass or volume mixing ratio over time due to wet deposition.
For exponential form A and B coefficients see Bakels et al. (2024, Table B2).
For Henry's law constants see Sander (2023) or https://henrys-law.org/.
Some species (e.g. SO2) require an effective Henry constant to account not only for physical solubility in water but also for chemical reactions, such as hydrolysis and ionization, which significantly enhance dissolution in aqueous solutions.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 5963 of file mptrac.c.

5968 {
5969
5970 /* Set timer... */
5971 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS");
5972
5973 /* Check quantity flags... */
5974 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5975 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5976
5977 /* Loop over particles... */
5978 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5979
5980 /* Check whether particle is below cloud top... */
5981 double pct;
5983 INTPOL_2D(pct, 1);
5984 if (!isfinite(pct) || atm->p[ip] <= pct)
5985 continue;
5986
5987 /* Get cloud bottom pressure... */
5988 double pcb;
5989 INTPOL_2D(pcb, 0);
5990
5991 /* Estimate precipitation rate (Pisso et al., 2019)... */
5992 double cl;
5993 INTPOL_2D(cl, 0);
5994 const double Is =
5995 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
5996 if (Is < 0.01)
5997 continue;
5998
5999 /* Check whether particle is inside or below cloud... */
6000 double lwc, rwc, iwc, swc;
6001 INTPOL_3D(lwc, 1);
6002 INTPOL_3D(rwc, 0);
6003 INTPOL_3D(iwc, 0);
6004 INTPOL_3D(swc, 0);
6005 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
6006
6007 /* Get temperature... */
6008 double t;
6009 INTPOL_3D(t, 0);
6010
6011 /* Calculate in-cloud scavenging coefficient... */
6012 double lambda = 0;
6013 if (inside) {
6014
6015 /* Calculate retention factor... */
6016 double eta;
6017 if (t > 273.15)
6018 eta = 1;
6019 else if (t <= 238.15)
6020 eta = ctl->wet_depo_ic_ret_ratio;
6021 else
6022 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
6023
6024 /* Use exponential dependency for particles (Bakels et al., 2024)... */
6025 if (ctl->wet_depo_ic_a > 0)
6026 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
6027
6028 /* Use Henry's law for gases... */
6029 else if (ctl->wet_depo_ic_h[0] > 0) {
6030
6031 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
6032 double h = ctl->wet_depo_ic_h[0]
6033 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
6034
6035 /* Use effective Henry's constant for SO2
6036 (Berglen, 2004; Simpson, 2012)... */
6037 if (ctl->wet_depo_so2_ph > 0) {
6038 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
6039 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
6040 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
6041 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
6042 }
6043
6044 /* Estimate depth of cloud layer... */
6045 const double dz = 1e3 * (Z(pct) - Z(pcb));
6046
6047 /* Calculate scavenging coefficient... */
6048 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
6049 }
6050 }
6051
6052 /* Calculate below-cloud scavenging coefficient... */
6053 else {
6054
6055 /* Calculate retention factor... */
6056 double eta;
6057 if (t > 270)
6058 eta = 1;
6059 else
6060 eta = ctl->wet_depo_bc_ret_ratio;
6061
6062 /* Use exponential dependency for particles (Bakels et al., 2024)... */
6063 if (ctl->wet_depo_bc_a > 0)
6064 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
6065
6066 /* Use Henry's law for gases... */
6067 else if (ctl->wet_depo_bc_h[0] > 0) {
6068
6069 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
6070 const double h = ctl->wet_depo_bc_h[0]
6071 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
6072
6073 /* Estimate depth of cloud layer... */
6074 const double dz = 1e3 * (Z(pct) - Z(pcb));
6075
6076 /* Calculate scavenging coefficient... */
6077 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
6078 }
6079 }
6080
6081 /* Calculate exponential decay of mass... */
6082 const double aux = exp(-cache->dt[ip] * lambda);
6083 if (ctl->qnt_m >= 0) {
6084 if (ctl->qnt_mloss_wet >= 0)
6085 atm->q[ctl->qnt_mloss_wet][ip]
6086 += atm->q[ctl->qnt_m][ip] * (1 - aux);
6087 atm->q[ctl->qnt_m][ip] *= aux;
6088 if (ctl->qnt_loss_rate >= 0)
6089 atm->q[ctl->qnt_loss_rate][ip] += lambda;
6090 }
6091 if (ctl->qnt_vmr >= 0)
6092 atm->q[ctl->qnt_vmr][ip] *= aux;
6093 }
6094}
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:3051
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:3045
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2465
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:3063
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:3042
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3060
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:3069
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3057
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:3066
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:3054
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:3048

◆ mptrac_alloc()

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

Allocates and initializes memory resources for MPTRAC.

This function handles memory allocation for various data structures and sets up GPU resources if available. It also creates the necessary data regions on GPUs for OpenACC-enabled execution.

Parameters
[out]ctlPointer to the control structure (ctl_t).
[out]cachePointer to the cache structure (cache_t).
[out]climPointer to the climatology structure (clim_t).
[out]met0Pointer to the first meteorology structure (met_t).
[out]met1Pointer to the second meteorology structure (met_t).
[out]atmPointer to the atmospheric structure (atm_t).
[out]ddpointer to an dd_t structure containing MPI information, including rank and neighbours.
Note
This function uses OpenACC for GPU initialization and memory management. If OpenACC is not enabled, the GPU-specific code is ignored.
Precondition
The function requires an environment supporting OpenACC for GPU operations. MPI support is optional but assumed if compiled with MPI.
Postcondition
Allocated structures are ready for use, and data regions on GPUs are initialized if OpenACC is enabled.
Exceptions
Runtimeerror if no GPU devices are available when OpenACC is enabled.
Author
Lars Hoffmann

Definition at line 6098 of file mptrac.c.

6105 {
6106
6107 /* Initialize GPU... */
6108#ifdef _OPENACC
6109 SELECT_TIMER("ACC_INIT", "INIT");
6110 int rank = 0;
6111#ifdef MPI
6112 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
6113#endif
6114 if (acc_get_num_devices(acc_device_nvidia) <= 0)
6115 ERRMSG("Not running on a GPU device!");
6116 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
6117 acc_device_nvidia);
6118 acc_device_t device_type = acc_get_device_type();
6119 acc_init(device_type);
6120#endif
6121
6122 /* Allocate... */
6123 SELECT_TIMER("ALLOC", "MEMORY");
6124 ALLOC(*ctl, ctl_t, 1);
6125 ALLOC(*cache, cache_t, 1);
6126 ALLOC(*clim, clim_t, 1);
6127 ALLOC(*met0, met_t, 1);
6128 ALLOC(*met1, met_t, 1);
6129 ALLOC(*atm, atm_t, 1);
6130 ALLOC(*dd, dd_t, 1);
6131
6132 /* Create data region on GPU... */
6133#ifdef _OPENACC
6134 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY");
6135 ctl_t *ctlup = *ctl;
6136 cache_t *cacheup = *cache;
6137 clim_t *climup = *clim;
6138 met_t *met0up = *met0;
6139 met_t *met1up = *met1;
6140 atm_t *atmup = *atm;
6141#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
6142#ifdef DD
6143 dd_t *ddup = *dd;
6144#pragma acc enter data create(ddup[:1])
6145#endif
6146#endif
6147}
Air parcel data.
Definition: mptrac.h:3341
Cache data structure.
Definition: mptrac.h:3396
Climatological data.
Definition: mptrac.h:3536
Control parameters.
Definition: mptrac.h:2284
Domain decomposition data structure.
Definition: mptrac.h:3772
Meteo data structure.
Definition: mptrac.h:3595

◆ mptrac_free()

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

Frees memory resources allocated for MPTRAC.

This function releases the memory allocated for various data structures and deletes any associated data regions on GPUs if OpenACC is enabled.

Parameters
[in]ctlPointer to the control structure (ctl_t) to be freed.
[in]cachePointer to the cache structure (cache_t) to be freed.
[in]climPointer to the climatology structure (clim_t) to be freed.
[in]met0Pointer to the first meteorology structure (met_t) to be freed.
[in]met1Pointer to the second meteorology structure (met_t) to be freed.
[in]atmPointer to the atmospheric structure (atm_t) to be freed.
[in]ddPointer to an dd_t structure containing MPI information, including rank and neighbours.
Note
This function uses OpenACC for GPU memory management. If OpenACC is not enabled, the GPU-specific code is ignored.
Precondition
All input pointers must point to valid allocated memory. The function assumes that the memory was allocated using compatible allocation methods.
Postcondition
All input pointers are freed, and the associated data regions on GPUs are deleted if OpenACC is enabled.
Warning
Ensure that the input pointers are not used after calling this function as they will be invalidated.
Author
Lars Hoffmann

Definition at line 6151 of file mptrac.c.

6158 {
6159
6160 /* Delete data region on GPU... */
6161#ifdef _OPENACC
6162 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY");
6163#pragma acc exit data delete(ctl,cache,clim,met0,met1,atm)
6164#ifdef DD
6165#pragma acc exit data delete(dd)
6166#endif
6167#endif
6168
6169 /* Free... */
6170 SELECT_TIMER("FREE", "MEMORY");
6171 free(atm);
6172 free(ctl);
6173 free(cache);
6174 free(clim);
6175 free(met0);
6176 free(met1);
6177
6178 /* Free MPI datatype... */
6179#ifdef DD
6180 MPI_Type_free(&dd->MPI_Particle);
6181#endif
6182 free(dd);
6183}

◆ mptrac_get_met()

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

Retrieves meteorological data for the specified time.

This function retrieves meteorological data for the given time t and updates the provided pointers to the met0 and met1 structures accordingly. It handles both the initialization and subsequent updates of the meteorological data based on the direction of time integration.

Parameters
ctlPointer to the control structure containing configuration settings.
climPointer to the climate structure.
tThe current time for which meteorological data is to be retrieved.
met0Pointer to the pointer of the first meteorological data structure.
met1Pointer to the pointer of the second meteorological data structure.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.

The function performs the following steps:

  • Initializes meteorological data on the first call or when the simulation restarts.
  • Reads new meteorological data when advancing forward or backward in time.
  • Swaps pointers to manage double buffering of the meteorological data.
  • Performs caching to optimize subsequent data retrieval.
  • Ensures consistency of the meteorological grids.
Note
This function utilizes GPU acceleration with OpenACC directives if enabled.
Ensure that ctl, clim, met0, and met1 are properly initialized before calling this function.
See also
get_met_filename
read_met
SELECT_TIMER
LOG
ERRMSG
WARN
Author
Lars Hoffmann

Definition at line 6187 of file mptrac.c.

6193 {
6194
6195 static int init;
6196
6197 met_t *mets;
6198
6199 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
6200
6201 /* Set timer... */
6202 SELECT_TIMER("GET_MET", "INPUT");
6203
6204 /* Init... */
6205 if (t == ctl->t_start || !init) {
6206 init = 1;
6207
6208 /* Read meteo data... */
6209 get_met_filename(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
6210 ctl->metbase, ctl->dt_met, filename);
6211 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
6212 ERRMSG("Cannot open file!");
6213
6214 get_met_filename(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
6215 ctl->metbase, ctl->dt_met, filename);
6216 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
6217 ERRMSG("Cannot open file!");
6218
6219 /* Update GPU... */
6220 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
6221 SELECT_TIMER("GET_MET", "INPUT");
6222
6223 /* Caching... */
6224 if (ctl->met_cache && t != ctl->t_stop) {
6225 get_met_filename(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
6226 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
6227 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6228 LOG(1, "Caching: %s", cachefile);
6229 if (system(cmd) != 0)
6230 WARN("Caching command failed!");
6231 }
6232 }
6233
6234 /* Read new data for forward trajectories... */
6235 if (t > (*met1)->time) {
6236
6237 /* Pointer swap... */
6238 mets = *met1;
6239 *met1 = *met0;
6240 *met0 = mets;
6241
6242 /* Read new meteo data... */
6243 get_met_filename(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
6244 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
6245 ERRMSG("Cannot open file!");
6246
6247 /* Update GPU... */
6248 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
6249 SELECT_TIMER("GET_MET", "INPUT");
6250
6251 /* Caching... */
6252 if (ctl->met_cache && t != ctl->t_stop) {
6253 get_met_filename(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
6254 cachefile);
6255 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6256 LOG(1, "Caching: %s", cachefile);
6257 if (system(cmd) != 0)
6258 WARN("Caching command failed!");
6259 }
6260 }
6261
6262 /* Read new data for backward trajectories... */
6263 if (t < (*met0)->time) {
6264
6265 /* Pointer swap... */
6266 mets = *met1;
6267 *met1 = *met0;
6268 *met0 = mets;
6269
6270 /* Read new meteo data... */
6271 get_met_filename(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
6272 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
6273 ERRMSG("Cannot open file!");
6274
6275 /* Update GPU... */
6276 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
6277 SELECT_TIMER("GET_MET", "INPUT");
6278
6279 /* Caching... */
6280 if (ctl->met_cache && t != ctl->t_stop) {
6281 get_met_filename(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
6282 cachefile);
6283 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6284 LOG(1, "Caching: %s", cachefile);
6285 if (system(cmd) != 0)
6286 WARN("Caching command failed!");
6287 }
6288 }
6289
6290 if ((*met0)->coord_type != (*met1)->coord_type)
6291 ERRMSG("Coordinate types do not match!");
6292
6293 /* Check that grids are consistent... */
6294 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
6295 if ((*met0)->nx != (*met1)->nx
6296 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
6297 ERRMSG("Meteo grid dimensions do not match!");
6298 for (int ix = 0; ix < (*met0)->nx; ix++)
6299 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
6300 ERRMSG("Meteo grid longitudes do not match!");
6301 for (int iy = 0; iy < (*met0)->ny; iy++)
6302 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
6303 ERRMSG("Meteo grid latitudes do not match!");
6304 for (int ip = 0; ip < (*met0)->np; ip++)
6305 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
6306 ERRMSG("Meteo grid pressure levels do not match!");
6307 }
6308}
void get_met_filename(const ctl_t *ctl, const double t, const int direct, const char *metbase, const double dt_met, char *filename)
Generates a formatted filename for meteorological data files based on the input parameters.
Definition: mptrac.c:2619
int mptrac_read_met(const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met, dd_t *dd)
Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.
Definition: mptrac.c:7436
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2163
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2793
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2628
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 6312 of file mptrac.c.

6317 {
6318
6319 /* Initialize timesteps... */
6320 module_timesteps_init(ctl, atm);
6321
6322 /* Initialize random number generator... */
6323 module_rng_init(ntask);
6324
6325 /* Update GPU memory... */
6326 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
6327}
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:5858
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:5535
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 6331 of file mptrac.c.

6334 {
6335
6336 int result;
6337
6338 /* Set timer... */
6339 SELECT_TIMER("READ_ATM", "INPUT");
6340
6341 /* Init... */
6342 atm->np = 0;
6343
6344 /* Write info... */
6345 LOG(1, "Read atmospheric data: %s", filename);
6346
6347 /* Read ASCII data... */
6348 if (ctl->atm_type == 0)
6349 result = read_atm_asc(filename, ctl, atm);
6350
6351 /* Read binary data... */
6352 else if (ctl->atm_type == 1)
6353 result = read_atm_bin(filename, ctl, atm);
6354
6355 /* Read netCDF data... */
6356 else if (ctl->atm_type == 2)
6357 result = read_atm_nc(filename, ctl, atm);
6358
6359 /* Read CLaMS data... */
6360 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
6361 result = read_atm_clams(filename, ctl, atm);
6362
6363 /* Error... */
6364 else
6365 ERRMSG("Atmospheric data type not supported!");
6366
6367 /* Check result... */
6368 if (result != 1)
6369 return 0;
6370
6371 /* Check number of air parcels... */
6372 if (atm->np < 1)
6373 ERRMSG("Can not read any data!");
6374
6375 /* Write info... */
6376 double mini, maxi;
6377 LOG(2, "Number of particles: %d", atm->np);
6378 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6379 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6380 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6381 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6382 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6383 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6384 LOG(2, "%s range: %g ... %g %s",
6385 ctl->met_coord_type == 0 ? "Longitude" : "X coordinate", mini, maxi,
6386 ctl->met_coord_type == 0 ? "deg" : "m");
6387 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6388 LOG(2, "%s range: %g ... %g %s",
6389 ctl->met_coord_type == 0 ? "Latitude" : "Y coordinate", mini, maxi,
6390 ctl->met_coord_type == 0 ? "deg" : "m");
6391 for (int iq = 0; iq < ctl->nq; iq++) {
6392 char msg[5 * LEN];
6393 sprintf(msg, "Quantity %s range: %s ... %s %s",
6394 ctl->qnt_name[iq], ctl->qnt_format[iq],
6395 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6396 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6397 LOG(2, msg, mini, maxi);
6398 }
6399
6400 /* Return success... */
6401 return 1;
6402}
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:8217
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:8098
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:8154
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:8056
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2303
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3104
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2300
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2294
Here is the call graph for this function:

◆ mptrac_read_clim()

void mptrac_read_clim ( const ctl_t ctl,
clim_t clim 
)

Reads various climatological data and populates the given climatology structure.

This function reads a range of climatological datasets based on the specified control settings and stores the data in the provided clim_t structure. It handles initialization of tropopause climatology, photolysis rates, and multiple gas species' climatologies and time series.

Parameters
ctlA pointer to the control structure (ctl_t) that specifies file names and parameters for climatology data.
climA pointer to the climatology structure (clim_t) that will be populated with the data.

This function performs the following steps:

  • Sets a timer for reading climatology data.
  • Initializes the tropopause climatology.
  • Reads photolysis rates if specified in ctl.
  • Reads HNO3 climatology if specified in ctl.
  • Reads OH climatology if specified in ctl and applies a diurnal correction if specified.
  • Reads H2O2, HO2, O(1D) climatologies if specified in ctl.
  • Reads time series data for various gases (CFC-10, CFC-11, CFC-12, N2O, SF6) if specified in ctl.

The function utilizes several helper functions:

  • clim_tropo_init for initializing tropopause climatology.
  • read_clim_photo for reading photolysis rates.
  • read_clim_zm for reading zonal mean climatologies.
  • clim_oh_diurnal_correction for applying diurnal correction to OH climatology.
  • read_clim_ts for reading time series data.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 6406 of file mptrac.c.

6408 {
6409
6410 /* Set timer... */
6411 SELECT_TIMER("READ_CLIM", "INPUT");
6412
6413 /* Init tropopause climatology... */
6414 clim_tropo_init(clim);
6415
6416 /* Read photolysis rates... */
6417 if (ctl->clim_photo[0] != '-')
6418 read_clim_photo(ctl->clim_photo, &clim->photo);
6419
6420 /* Read HNO3 climatology... */
6421 if (ctl->clim_hno3_filename[0] != '-')
6422 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
6423
6424 /* Read OH climatology... */
6425 if (ctl->clim_oh_filename[0] != '-') {
6426 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
6427 if (ctl->oh_chem_beta > 0)
6428 clim_oh_diurnal_correction(ctl, clim);
6429 }
6430
6431 /* Read H2O2 climatology... */
6432 if (ctl->clim_h2o2_filename[0] != '-')
6433 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
6434
6435 /* Read HO2 climatology... */
6436 if (ctl->clim_ho2_filename[0] != '-')
6437 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
6438
6439 /* Read O(1D) climatology... */
6440 if (ctl->clim_o1d_filename[0] != '-')
6441 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
6442
6443 /* Read CFC-10 time series... */
6444 if (ctl->clim_ccl4_timeseries[0] != '-')
6446
6447 /* Read CFC-11 time series... */
6448 if (ctl->clim_ccl3f_timeseries[0] != '-')
6450
6451 /* Read CFC-12 time series... */
6452 if (ctl->clim_ccl2f2_timeseries[0] != '-')
6454
6455 /* Read N2O time series... */
6456 if (ctl->clim_n2o_timeseries[0] != '-')
6457 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
6458
6459 /* Read SF6 time series... */
6460 if (ctl->clim_sf6_timeseries[0] != '-')
6461 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
6462}
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:8250
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:8369
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:8423
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:241
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:124
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2931
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2934
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2919
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2928
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2925
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2922
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 6466 of file mptrac.c.

6470 {
6471
6472 /* Set timer... */
6473 SELECT_TIMER("READ_CTL", "INPUT");
6474
6475 /* Write info... */
6476 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
6477 "(executable: %s | version: %s | compiled: %s, %s)\n",
6478 argv[0], VERSION, __DATE__, __TIME__);
6479
6480 /* Initialize quantity indices... */
6481 ctl->qnt_idx = -1;
6482 ctl->qnt_ens = -1;
6483 ctl->qnt_stat = -1;
6484 ctl->qnt_m = -1;
6485 ctl->qnt_vmr = -1;
6486 ctl->qnt_rp = -1;
6487 ctl->qnt_rhop = -1;
6488 ctl->qnt_ps = -1;
6489 ctl->qnt_ts = -1;
6490 ctl->qnt_zs = -1;
6491 ctl->qnt_us = -1;
6492 ctl->qnt_vs = -1;
6493 ctl->qnt_ess = -1;
6494 ctl->qnt_nss = -1;
6495 ctl->qnt_shf = -1;
6496 ctl->qnt_lsm = -1;
6497 ctl->qnt_sst = -1;
6498 ctl->qnt_pbl = -1;
6499 ctl->qnt_pt = -1;
6500 ctl->qnt_tt = -1;
6501 ctl->qnt_zt = -1;
6502 ctl->qnt_h2ot = -1;
6503 ctl->qnt_zg = -1;
6504 ctl->qnt_p = -1;
6505 ctl->qnt_t = -1;
6506 ctl->qnt_rho = -1;
6507 ctl->qnt_u = -1;
6508 ctl->qnt_v = -1;
6509 ctl->qnt_w = -1;
6510 ctl->qnt_h2o = -1;
6511 ctl->qnt_o3 = -1;
6512 ctl->qnt_lwc = -1;
6513 ctl->qnt_rwc = -1;
6514 ctl->qnt_iwc = -1;
6515 ctl->qnt_swc = -1;
6516 ctl->qnt_cc = -1;
6517 ctl->qnt_pct = -1;
6518 ctl->qnt_pcb = -1;
6519 ctl->qnt_cl = -1;
6520 ctl->qnt_plcl = -1;
6521 ctl->qnt_plfc = -1;
6522 ctl->qnt_pel = -1;
6523 ctl->qnt_cape = -1;
6524 ctl->qnt_cin = -1;
6525 ctl->qnt_o3c = -1;
6526 ctl->qnt_hno3 = -1;
6527 ctl->qnt_oh = -1;
6528 ctl->qnt_h2o2 = -1;
6529 ctl->qnt_ho2 = -1;
6530 ctl->qnt_o1d = -1;
6531 ctl->qnt_mloss_oh = -1;
6532 ctl->qnt_mloss_h2o2 = -1;
6533 ctl->qnt_mloss_kpp = -1;
6534 ctl->qnt_mloss_wet = -1;
6535 ctl->qnt_mloss_dry = -1;
6536 ctl->qnt_mloss_decay = -1;
6537 ctl->qnt_loss_rate = -1;
6538 ctl->qnt_psat = -1;
6539 ctl->qnt_psice = -1;
6540 ctl->qnt_pw = -1;
6541 ctl->qnt_sh = -1;
6542 ctl->qnt_rh = -1;
6543 ctl->qnt_rhice = -1;
6544 ctl->qnt_theta = -1;
6545 ctl->qnt_zeta = -1;
6546 ctl->qnt_zeta_d = -1;
6547 ctl->qnt_zeta_dot = -1;
6548 ctl->qnt_eta = -1;
6549 ctl->qnt_eta_dot = -1;
6550 ctl->qnt_tvirt = -1;
6551 ctl->qnt_lapse = -1;
6552 ctl->qnt_vh = -1;
6553 ctl->qnt_vz = -1;
6554 ctl->qnt_pv = -1;
6555 ctl->qnt_tdew = -1;
6556 ctl->qnt_tice = -1;
6557 ctl->qnt_tsts = -1;
6558 ctl->qnt_tnat = -1;
6559 ctl->qnt_Cx = -1;
6560 ctl->qnt_Ch2o = -1;
6561 ctl->qnt_Co3 = -1;
6562 ctl->qnt_Cco = -1;
6563 ctl->qnt_Coh = -1;
6564 ctl->qnt_Ch = -1;
6565 ctl->qnt_Cho2 = -1;
6566 ctl->qnt_Ch2o2 = -1;
6567 ctl->qnt_Co1d = -1;
6568 ctl->qnt_Co3p = -1;
6569 ctl->qnt_Cccl4 = -1;
6570 ctl->qnt_Cccl3f = -1;
6571 ctl->qnt_Cccl2f2 = -1;
6572 ctl->qnt_Cn2o = -1;
6573 ctl->qnt_Csf6 = -1;
6574 ctl->qnt_aoa = -1;
6575 ctl->qnt_Arn222 = -1;
6576 ctl->qnt_Apb210 = -1;
6577 ctl->qnt_Abe7 = -1;
6578 ctl->qnt_Acs137 = -1;
6579 ctl->qnt_Ai131 = -1;
6580 ctl->qnt_Axe133 = -1;
6581 ctl->qnt_current_subdomain = -1;
6582 ctl->qnt_target_subdomain = -1;
6583
6584 /* Read quantities... */
6585 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
6586 if (ctl->nq > NQ)
6587 ERRMSG("Too many quantities!");
6588 for (int iq = 0; iq < ctl->nq; iq++) {
6589
6590 /* Read quantity name and format... */
6591 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
6592 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
6593 ctl->qnt_longname[iq]);
6594 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
6595 ctl->qnt_format[iq]);
6596 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
6597 sprintf(ctl->qnt_format[iq], "%%.2f");
6598
6599 /* Try to identify quantity... */
6600 SET_QNT(qnt_idx, "idx", "particle index", "-")
6601 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
6602 SET_QNT(qnt_stat, "stat", "station flag", "-")
6603 SET_QNT(qnt_m, "m", "mass", "kg")
6604 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
6605 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
6606 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
6607 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
6608 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
6609 SET_QNT(qnt_zs, "zs", "surface height", "km")
6610 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
6611 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
6612 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
6613 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
6614 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
6615 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
6616 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
6617 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
6618 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
6619 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
6620 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
6621 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
6622 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
6623 SET_QNT(qnt_p, "p", "pressure", "hPa")
6624 SET_QNT(qnt_t, "t", "temperature", "K")
6625 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
6626 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
6627 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
6628 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
6629 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
6630 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
6631 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
6632 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
6633 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
6634 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
6635 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
6636 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
6637 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
6638 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
6639 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
6640 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
6641 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
6642 SET_QNT(qnt_cape, "cape", "convective available potential energy",
6643 "J/kg")
6644 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
6645 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
6646 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
6647 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
6648 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
6649 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
6650 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
6651 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
6652 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
6653 "mass loss due to H2O2 chemistry", "kg")
6654 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
6655 "kg")
6656 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
6657 "kg")
6658 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
6659 "kg")
6660 SET_QNT(qnt_mloss_decay, "mloss_decay",
6661 "mass loss due to exponential decay", "kg")
6662 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
6663 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
6664 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
6665 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
6666 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
6667 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
6668 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
6669 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
6670 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
6671 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
6672 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
6673 "K/day")
6674 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
6675 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
6676 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
6677 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
6678 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
6679 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
6680 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
6681 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
6682 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
6683 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
6684 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
6685 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
6686 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
6687 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
6688 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
6689 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
6690 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
6691 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
6692 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
6693 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
6694 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
6695 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
6696 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
6697 "ppv")
6698 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
6699 "ppv")
6700 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
6701 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
6702 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
6703 SET_QNT(qnt_Arn222, "Arn222", "Rn-222 activity", "Bq")
6704 SET_QNT(qnt_Apb210, "Apb210", "Pb-210 activity", "Bq")
6705 SET_QNT(qnt_Abe7, "Abe7", "Be-7 activity", "Bq")
6706 SET_QNT(qnt_Acs137, "Acs137", "Cs-137 activity", "Bq")
6707 SET_QNT(qnt_Ai131, "Ai131", "I-131 activity", "Bq")
6708 SET_QNT(qnt_Axe133, "Axe133", "Xe-133 activity", "Bq")
6709 SET_QNT(qnt_current_subdomain, "current_subdomain",
6710 "current subdomain rank", "-")
6711 SET_QNT(qnt_target_subdomain, "target_subdomain",
6712 "target subdomain rank", "-")
6713 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
6714 }
6715
6716 ctl->met_coord_type =
6717 (int) scan_ctl(filename, argc, argv, "MET_COORD_TYPE", -1, "0", NULL);
6718 if (ctl->met_coord_type < 0 || ctl->met_coord_type > 1)
6719 ERRMSG("MET_COORD_TYPE must be 0 or 1!");
6720 ctl->met_utm_ref_lat = 0.0;
6721 ctl->met_utm_ref_lon = 0.0;
6722 if (ctl->met_coord_type == 1) {
6723 ctl->met_utm_ref_lat =
6724 scan_ctl(filename, argc, argv, "MET_UTM_REF_LAT", -1, "", NULL);
6725 ctl->met_utm_ref_lon =
6726 scan_ctl(filename, argc, argv, "MET_UTM_REF_LON", -1, "", NULL);
6727 }
6728
6729 /* Vertical coordinate and velocity... */
6730 ctl->advect_vert_coord =
6731 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
6732 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
6733 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
6734
6735 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
6736 ERRMSG("Add quantity zeta for diabatic advection!");
6737 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
6738 ERRMSG("Add quantity eta for etadot avection!");
6739
6740 ctl->met_vert_coord =
6741 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
6742 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
6743 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
6744
6745 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
6746 ERRMSG
6747 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
6748 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
6749 ERRMSG
6750 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
6751
6752 ctl->met_gp2z =
6753 (int) scan_ctl(filename, argc, argv, "MET_GP2Z", -1, "0", NULL);
6754 if (ctl->met_gp2z != 0 && ctl->met_gp2z != 1)
6755 ERRMSG("Set MET_GP2Z to 0 or 1!");
6756
6757 /* Time steps of simulation... */
6758 ctl->direction =
6759 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
6760 if (ctl->direction != -1 && ctl->direction != 1)
6761 ERRMSG("Set DIRECTION to -1 or 1!");
6762 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
6763 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
6764
6765 /* Meteo data... */
6766 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
6767 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
6768 if (ctl->dt_mod > ctl->dt_met)
6769 ERRMSG("DT_MOD must not exceed DT_MET!");
6770 ctl->met_convention =
6771 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
6772 ctl->met_type =
6773 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
6774 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
6775 ERRMSG
6776 ("Please use meteo files in netcdf format for diabatic calculations.");
6777 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
6778 ERRMSG
6779 ("Please use meteo files in netcdf format for etadot calculations.");
6780 ctl->met_clams =
6781 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
6782 ctl->met_nc_scale =
6783 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
6784 ctl->met_nc_level =
6785 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
6786 ctl->met_nc_quant =
6787 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
6788 ctl->met_zstd_level =
6789 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "-3", NULL);
6790 ctl->met_zstd_nworkers =
6791 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_NWORKERS", -1, "4", NULL);
6792 ctl->met_lz4_accel =
6793 (int) scan_ctl(filename, argc, argv, "MET_LZ4_ACCEL", -1, "8", NULL);
6794 ctl->met_pck_zstd =
6795 (int) scan_ctl(filename, argc, argv, "MET_PCK_ZSTD", -1, "0", NULL);
6796 if (ctl->met_pck_zstd != 0 && ctl->met_pck_zstd != 1)
6797 ERRMSG("Set MET_PCK_ZSTD to 0 or 1!");
6798#ifndef ZSTD
6799 if (ctl->met_type == 2 && ctl->met_pck_zstd)
6800 ERRMSG("MET_PCK_ZSTD requires MPTRAC to be compiled with ZSTD support!");
6801#endif
6802 const int def_lossy_scale =
6803 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", -1, "0", NULL);
6804 for (int i = 0; i < METVAR; i++) {
6805 char defprec_zfp[LEN] = "7", deftol_zfp[LEN] = "0.0";
6806 char defprec_sz3[LEN] = "6", deftol_sz3[LEN] = "0.0";
6807 if (i == 0) { /* geopotential height */
6808 sprintf(defprec_zfp, "12");
6809 sprintf(defprec_sz3, "11");
6810 } else if (i == 1) { /* temperature */
6811 sprintf(defprec_zfp, "11");
6812 sprintf(defprec_sz3, "7");
6813 } else if (i == 2 || i == 3) { /* horizontal wind */
6814 sprintf(defprec_zfp, "7");
6815 sprintf(defprec_sz3, "7");
6816 } else if (i == 4) { /* vertical wind */
6817 sprintf(defprec_zfp, "6");
6818 sprintf(defprec_sz3, "13");
6819 } else if (i == 5) { /* potential vorticity */
6820 sprintf(defprec_zfp, "7");
6821 sprintf(defprec_sz3, "20");
6822 } else if (i == 6) { /* water vapor */
6823 sprintf(defprec_zfp, "10");
6824 sprintf(defprec_sz3, "18");
6825 } else if (i == 7) { /* ozone */
6826 sprintf(defprec_zfp, "9");
6827 sprintf(defprec_sz3, "10");
6828 } else if (i >= 8 && i <= 11) { /* cloud water fields */
6829 sprintf(defprec_zfp, "6");
6830 sprintf(defprec_sz3, "13");
6831 } else if (i == 12) { /* cloud cover */
6832 sprintf(defprec_zfp, "9");
6833 sprintf(defprec_sz3, "6");
6834 }
6835 ctl->met_zfp_prec[i] =
6836 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", i, defprec_zfp,
6837 NULL);
6838 ctl->met_zfp_tol[i] =
6839 scan_ctl(filename, argc, argv, "MET_ZFP_TOL", i, deftol_zfp, NULL);
6840 ctl->met_sz3_prec[i] =
6841 (int) scan_ctl(filename, argc, argv, "MET_SZ3_PREC", i, defprec_sz3,
6842 NULL);
6843 ctl->met_sz3_tol[i] =
6844 scan_ctl(filename, argc, argv, "MET_SZ3_TOL", i, deftol_sz3, NULL);
6845 char defscale[LEN];
6846 snprintf(defscale, LEN, "%d", def_lossy_scale);
6847 ctl->met_lossy_scale[i] =
6848 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", i, defscale,
6849 NULL);
6850 if (ctl->met_lossy_scale[i] < 0 || ctl->met_lossy_scale[i] > 1)
6851 ERRMSG("Set MET_LOSSY_SCALE to 0 or 1!");
6852 }
6853
6854 /* Scan compression diagnostics file... */
6855 scan_ctl(filename, argc, argv, "MET_COMP_LOGFILE", -1, "-",
6856 ctl->met_comp_logfile);
6857 ctl->met_cms_batch =
6858 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
6859 ctl->met_cms_zstd =
6860 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
6861 ctl->met_cms_nd0x =
6862 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
6863 ctl->met_cms_nd0y =
6864 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
6865 ctl->met_cms_maxlev =
6866 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
6867 for (int i = 0; i < METVAR; i++) {
6868 char defeps[LEN] = "1.0";
6869 if (i == 1 || i == 2 || i == 3)
6870 sprintf(defeps, "0.05");
6871 ctl->met_cms_eps[i] =
6872 scan_ctl(filename, argc, argv, "MET_CMS_EPS", i, defeps, NULL);
6873 }
6874 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
6875 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
6876 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
6877 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
6878 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
6879 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
6880 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
6881 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
6882 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
6883 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
6884 ctl->met_detrend =
6885 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
6886 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
6887 if (ctl->met_np > EP)
6888 ERRMSG("Too many pressure levels!");
6889 ctl->met_press_level_def =
6890 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
6891 NULL);
6892 if (ctl->met_press_level_def >= 0) {
6893 level_definitions(ctl);
6894 } else {
6895 if (ctl->met_np > 0) {
6896 for (int ip = 0; ip < ctl->met_np; ip++)
6897 ctl->met_p[ip] =
6898 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
6899 }
6900 }
6901 ctl->met_nlev =
6902 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
6903 if (ctl->met_nlev > EP)
6904 ERRMSG("Too many model levels!");
6905 for (int ip = 0; ip < ctl->met_nlev; ip++)
6906 ctl->met_lev_hyam[ip] =
6907 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
6908 for (int ip = 0; ip < ctl->met_nlev; ip++)
6909 ctl->met_lev_hybm[ip] =
6910 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
6911 ctl->met_geopot_sx =
6912 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
6913 ctl->met_geopot_sy =
6914 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
6915 ctl->met_relhum =
6916 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
6917 ctl->met_cape =
6918 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
6919 if (ctl->met_cape < 0 || ctl->met_cape > 1)
6920 ERRMSG("Set MET_CAPE to 0 or 1!");
6921 ctl->met_pbl =
6922 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
6923 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
6924 ERRMSG("Set MET_PBL to 0 ... 3!");
6925 ctl->met_pbl_min =
6926 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
6927 ctl->met_pbl_max =
6928 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
6929 ctl->met_tropo =
6930 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
6931 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
6932 ERRMSG("Set MET_TROPO to 0 ... 5!");
6933 ctl->met_tropo_pv =
6934 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
6935 ctl->met_tropo_theta =
6936 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
6937 ctl->met_tropo_spline =
6938 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
6939 ctl->met_dt_out =
6940 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
6941 ctl->met_cache =
6942 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
6943 ctl->met_mpi_share =
6944 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
6945
6946 /* Sorting... */
6947 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
6948
6949 /* Isosurface parameters... */
6950 ctl->isosurf =
6951 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
6952 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
6953
6954 /* Random number generator... */
6955 ctl->rng_type =
6956 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
6957 if (ctl->rng_type < 0 || ctl->rng_type > 2)
6958 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
6959
6960 /* Advection parameters... */
6961 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
6962 if (!(ctl->advect == 1 || ctl->advect == 2 || ctl->advect == 4))
6963 ERRMSG("Set ADVECT to 1, 2, or 4!");
6964
6965 /* Diffusion parameters... */
6966 ctl->diffusion
6967 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
6968 if (ctl->diffusion < 0 || ctl->diffusion > 1)
6969 ERRMSG("Set DIFFUSION to 0 or 1!");
6970 ctl->turb_pbl_scheme =
6971 (int) scan_ctl(filename, argc, argv, "TURB_PBL_SCHEME", -1, "0", NULL);
6972 if (ctl->turb_pbl_scheme < 0 || ctl->turb_pbl_scheme > 1)
6973 ERRMSG("Set TURB_PBL_SCHEME to 0 or 1!");
6974 ctl->turb_dx_pbl =
6975 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
6976 ctl->turb_dx_trop =
6977 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
6978 ctl->turb_dx_strat =
6979 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
6980 ctl->turb_dz_pbl =
6981 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
6982 ctl->turb_dz_trop =
6983 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
6984 ctl->turb_dz_strat =
6985 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
6986 ctl->turb_mesox =
6987 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
6988 ctl->turb_mesoz =
6989 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
6990 ctl->turb_pbl_trans =
6991 scan_ctl(filename, argc, argv, "TURB_PBL_TRANS", -1, "0", NULL);
6992 if (ctl->turb_pbl_trans < 0 || ctl->turb_pbl_trans > 1)
6993 ERRMSG("TURB_PBL_TRANS must be in the range [0, 1]!");
6994
6995 /* Convection... */
6996 ctl->conv_mix_pbl
6997 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
6998 ctl->conv_pbl_trans
6999 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
7000 if (ctl->conv_pbl_trans < 0 || ctl->conv_pbl_trans > 1)
7001 ERRMSG("CONV_PBL_TRANS must be in the range [0, 1]!");
7002 ctl->conv_cape
7003 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
7004 ctl->conv_cin
7005 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
7006 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
7007
7008 /* Boundary conditions... */
7009 ctl->bound_mass =
7010 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
7011 ctl->bound_mass_trend =
7012 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
7013 ctl->bound_vmr =
7014 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
7015 ctl->bound_vmr_trend =
7016 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
7017 ctl->bound_lat0 =
7018 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
7019 ctl->bound_lat1 =
7020 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
7021 ctl->bound_p0 =
7022 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
7023 ctl->bound_p1 =
7024 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
7025 ctl->bound_dps =
7026 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
7027 ctl->bound_dzs =
7028 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
7029 ctl->bound_zetas =
7030 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
7031 ctl->bound_pbl =
7032 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
7033
7034 /* Species parameters... */
7035 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
7036 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
7037 ctl->molmass = 120.907;
7038 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
7039 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
7040 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
7041 ctl->molmass = 137.359;
7042 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
7043 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
7044 } else if (strcasecmp(ctl->species, "CH4") == 0) {
7045 ctl->molmass = 16.043;
7046 ctl->oh_chem_reaction = 2;
7047 ctl->oh_chem[0] = 2.45e-12;
7048 ctl->oh_chem[1] = 1775;
7049 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
7050 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
7051 } else if (strcasecmp(ctl->species, "CO") == 0) {
7052 ctl->molmass = 28.01;
7053 ctl->oh_chem_reaction = 3;
7054 ctl->oh_chem[0] = 6.9e-33;
7055 ctl->oh_chem[1] = 2.1;
7056 ctl->oh_chem[2] = 1.1e-12;
7057 ctl->oh_chem[3] = -1.3;
7058 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
7059 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
7060 } else if (strcasecmp(ctl->species, "CO2") == 0) {
7061 ctl->molmass = 44.009;
7062 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
7063 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
7064 } else if (strcasecmp(ctl->species, "H2O") == 0) {
7065 ctl->molmass = 18.01528;
7066 } else if (strcasecmp(ctl->species, "N2O") == 0) {
7067 ctl->molmass = 44.013;
7068 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
7069 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
7070 } else if (strcasecmp(ctl->species, "NH3") == 0) {
7071 ctl->molmass = 17.031;
7072 ctl->oh_chem_reaction = 2;
7073 ctl->oh_chem[0] = 1.7e-12;
7074 ctl->oh_chem[1] = 710;
7075 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
7076 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
7077 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
7078 ctl->molmass = 63.012;
7079 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
7080 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
7081 } else if (strcasecmp(ctl->species, "NO") == 0) {
7082 ctl->molmass = 30.006;
7083 ctl->oh_chem_reaction = 3;
7084 ctl->oh_chem[0] = 7.1e-31;
7085 ctl->oh_chem[1] = 2.6;
7086 ctl->oh_chem[2] = 3.6e-11;
7087 ctl->oh_chem[3] = 0.1;
7088 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
7089 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
7090 } else if (strcasecmp(ctl->species, "NO2") == 0) {
7091 ctl->molmass = 46.005;
7092 ctl->oh_chem_reaction = 3;
7093 ctl->oh_chem[0] = 1.8e-30;
7094 ctl->oh_chem[1] = 3.0;
7095 ctl->oh_chem[2] = 2.8e-11;
7096 ctl->oh_chem[3] = 0.0;
7097 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
7098 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
7099 } else if (strcasecmp(ctl->species, "O3") == 0) {
7100 ctl->molmass = 47.997;
7101 ctl->oh_chem_reaction = 2;
7102 ctl->oh_chem[0] = 1.7e-12;
7103 ctl->oh_chem[1] = 940;
7104 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
7105 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
7106 } else if (strcasecmp(ctl->species, "SF6") == 0) {
7107 ctl->molmass = 146.048;
7108 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
7109 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
7110 } else if (strcasecmp(ctl->species, "SO2") == 0) {
7111 ctl->molmass = 64.066;
7112 ctl->oh_chem_reaction = 3;
7113 ctl->oh_chem[0] = 2.9e-31;
7114 ctl->oh_chem[1] = 4.1;
7115 ctl->oh_chem[2] = 1.7e-12;
7116 ctl->oh_chem[3] = -0.2;
7117 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
7118 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
7119 }
7120
7121 /* Molar mass... */
7122 char defstr[LEN];
7123 sprintf(defstr, "%g", ctl->molmass);
7124 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
7125
7126 /* OH chemistry... */
7127 sprintf(defstr, "%d", ctl->oh_chem_reaction);
7128 ctl->oh_chem_reaction =
7129 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
7130 NULL);
7131 for (int ip = 0; ip < 4; ip++) {
7132 sprintf(defstr, "%g", ctl->oh_chem[ip]);
7133 ctl->oh_chem[ip] =
7134 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
7135 }
7136 ctl->oh_chem_beta =
7137 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
7138
7139 /* H2O2 chemistry... */
7140 ctl->h2o2_chem_reaction =
7141 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
7142
7143 /* KPP chemistry... */
7144 ctl->kpp_chem =
7145 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
7146 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
7147
7148 /* First order tracer chemistry... */
7149 ctl->tracer_chem =
7150 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
7151
7152 /* Radioactive decay... */
7153 ctl->radio_decay =
7154 (int) scan_ctl(filename, argc, argv, "RADIO_DECAY", -1, "0", NULL);
7155
7156 /* Wet deposition... */
7157 for (int ip = 0; ip < 2; ip++) {
7158 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
7159 ctl->wet_depo_ic_h[ip] =
7160 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
7161 }
7162 for (int ip = 0; ip < 1; ip++) {
7163 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
7164 ctl->wet_depo_bc_h[ip] =
7165 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
7166 }
7167 ctl->wet_depo_so2_ph =
7168 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
7169 ctl->wet_depo_ic_a =
7170 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
7171 ctl->wet_depo_ic_b =
7172 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
7173 ctl->wet_depo_bc_a =
7174 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
7175 ctl->wet_depo_bc_b =
7176 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
7177 ctl->wet_depo_pre[0] =
7178 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
7179 ctl->wet_depo_pre[1] =
7180 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
7182 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
7184 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
7185
7186 /* Dry deposition... */
7187 ctl->dry_depo_vdep =
7188 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
7189 ctl->dry_depo_dp =
7190 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
7191
7192 /* Climatological data... */
7193 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
7194 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
7195 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
7196 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
7197 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
7198 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
7199 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
7200 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
7201 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
7202 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
7203 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
7204 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
7205 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
7206 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
7207 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
7208 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
7209 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
7210 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
7211 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
7212 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
7213 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
7214 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
7215
7216 /* Mixing... */
7217 ctl->mixing_dt =
7218 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
7219 ctl->mixing_trop =
7220 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
7221 ctl->mixing_strat =
7222 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
7223 ctl->mixing_z0 =
7224 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
7225 ctl->mixing_z1 =
7226 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
7227 ctl->mixing_nz =
7228 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
7229 ctl->mixing_lon0 =
7230 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
7231 ctl->mixing_lon1 =
7232 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
7233 ctl->mixing_nx =
7234 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
7235 ctl->mixing_lat0 =
7236 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
7237 ctl->mixing_lat1 =
7238 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
7239 ctl->mixing_ny =
7240 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
7241
7242 /* Chemistry grid... */
7243 ctl->chemgrid_z0 =
7244 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
7245 ctl->chemgrid_z1 =
7246 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
7247 ctl->chemgrid_nz =
7248 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
7249 ctl->chemgrid_lon0 =
7250 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
7251 ctl->chemgrid_lon1 =
7252 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
7253 ctl->chemgrid_nx =
7254 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
7255 ctl->chemgrid_lat0 =
7256 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
7257 ctl->chemgrid_lat1 =
7258 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
7259 ctl->chemgrid_ny =
7260 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
7261
7262 /* Exponential decay... */
7263 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
7264 ctl->tdec_strat =
7265 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
7266
7267 /* PSC analysis... */
7268 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
7269 ctl->psc_hno3 =
7270 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
7271
7272 /* Output of atmospheric data... */
7273 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
7274 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
7275 ctl->atm_dt_out =
7276 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
7277 ctl->atm_filter =
7278 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
7279 ctl->atm_stride =
7280 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
7281 ctl->atm_type =
7282 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
7283 ctl->atm_type_out =
7284 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
7285 if (ctl->atm_type_out == -1)
7286 ctl->atm_type_out = ctl->atm_type;
7287 ctl->atm_nc_level =
7288 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
7289 for (int iq = 0; iq < ctl->nq; iq++)
7290 ctl->atm_nc_quant[iq] =
7291 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
7292 ctl->obs_type =
7293 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
7294
7295 /* Output of CSI data... */
7296 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
7297 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
7298 ctl->csi_dt_out =
7299 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
7300 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
7301 ctl->csi_obsmin =
7302 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
7303 ctl->csi_modmin =
7304 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
7305 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
7306 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
7307 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
7308 ctl->csi_lon0 =
7309 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
7310 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
7311 ctl->csi_nx =
7312 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
7313 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
7314 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
7315 ctl->csi_ny =
7316 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
7317
7318 /* Output of ensemble data... */
7319 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
7320 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
7321 ctl->ens_dt_out =
7322 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
7323
7324 /* Output of grid data... */
7325 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
7326 ctl->grid_basename);
7327 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
7328 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
7329 ctl->grid_dt_out =
7330 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
7331 ctl->grid_sparse =
7332 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
7333 ctl->grid_nc_level =
7334 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
7335 for (int iq = 0; iq < ctl->nq; iq++)
7336 ctl->grid_nc_quant[iq] =
7337 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
7338 ctl->grid_stddev =
7339 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
7340 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
7341 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
7342 ctl->grid_nz =
7343 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
7344 ctl->grid_lon0 =
7345 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
7346 ctl->grid_lon1 =
7347 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
7348 ctl->grid_nx =
7349 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
7350 ctl->grid_lat0 =
7351 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
7352 ctl->grid_lat1 =
7353 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
7354 ctl->grid_ny =
7355 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
7356 ctl->grid_type =
7357 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
7358
7359 /* Output of profile data... */
7360 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
7361 ctl->prof_basename);
7362 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
7363 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
7364 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
7365 ctl->prof_nz =
7366 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
7367 ctl->prof_lon0 =
7368 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
7369 ctl->prof_lon1 =
7370 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
7371 ctl->prof_nx =
7372 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
7373 ctl->prof_lat0 =
7374 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
7375 ctl->prof_lat1 =
7376 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
7377 ctl->prof_ny =
7378 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
7379
7380 /* Output of sample data... */
7381 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
7382 ctl->sample_basename);
7383 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
7384 ctl->sample_kernel);
7385 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
7386 ctl->sample_obsfile);
7387 ctl->sample_dx =
7388 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
7389 ctl->sample_dz =
7390 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
7391
7392 /* Output of station data... */
7393 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
7394 ctl->stat_basename);
7395 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
7396 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
7397 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
7398 ctl->stat_t0 =
7399 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
7400 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
7401
7402 /* Output of VTK data... */
7403 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
7404 ctl->vtk_dt_out =
7405 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
7406 ctl->vtk_stride =
7407 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
7408 ctl->vtk_scale =
7409 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
7410 ctl->vtk_offset =
7411 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
7412 ctl->vtk_sphere =
7413 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
7414
7415 /* Domain decomposition... */
7416#ifdef DD
7417 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "1", NULL);
7418#else
7419 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
7420#endif
7421
7423 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
7424 (ctl->dd == 1) ? "2" : "1", NULL);
7425 ctl->dd_subdomains_zonal =
7426 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
7427 (ctl->dd == 1) ? "2" : "1", NULL);
7428 ctl->dd_halos_size =
7429 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
7430 ctl->dd_sort_dt =
7431 (double) scan_ctl(filename, argc, argv, "DD_SORT_DT", -1, "1800", NULL);
7432}
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:3342
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:12110
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:354
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:364
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1793
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3202
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2396
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3163
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3130
int qnt_target_subdomain
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2609
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2660
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2429
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3139
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2375
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3326
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3091
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2408
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3133
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2417
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3154
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2384
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3280
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2803
double stat_r
Search radius around station [km].
Definition: mptrac.h:3286
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3157
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3310
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2771
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2405
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2483
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3229
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3205
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2723
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2790
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2447
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2519
char species[LEN]
Species.
Definition: mptrac.h:2907
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3148
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3160
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2768
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2399
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3190
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3208
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3220
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2330
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2426
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3211
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2453
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2787
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3265
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2513
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2759
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3181
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2351
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2495
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3292
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3124
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3226
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3151
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2357
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3196
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2480
int radio_decay
Switch for radioactive decay module (0=off, 1=on).
Definition: mptrac.h:3039
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2756
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2729
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2327
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3232
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2333
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3235
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3127
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2765
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3136
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2726
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3178
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3238
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2390
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2781
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3244
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2312
double dd_sort_dt
Sorting time interval for the compactification.
Definition: mptrac.h:3329
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2796
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2522
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2450
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3145
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3289
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3317
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3109
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2705
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2747
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:3033
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3121
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2348
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2339
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3298
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2868
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3268
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2441
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3175
char met_comp_logfile[LEN]
Filename for per-level compression diagnostics ("-" disables output).
Definition: mptrac.h:2696
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2369
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2489
int met_gp2z
Convert surface geopotential to geopotential height (0=no, 1=yes).
Definition: mptrac.h:2650
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2774
int met_dx
Stride for longitudes.
Definition: mptrac.h:2717
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2634
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2501
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:3036
int diffusion
Diffusion switch (0=off, 1=on).
Definition: mptrac.h:2823
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2372
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3307
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2387
double met_zfp_tol[METVAR]
ZFP compression tolerance.
Definition: mptrac.h:2684
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2444
int met_sz3_prec[METVAR]
SZ3 compression precision.
Definition: mptrac.h:2687
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2393
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3253
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2492
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2381
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3274
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3118
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3193
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2336
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3214
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:3088
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2360
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2420
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3241
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2750
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2378
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3097
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:3030
int met_lz4_accel
LZ4 acceleration factor (>=1, default=8).
Definition: mptrac.h:2675
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3169
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:2647
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3142
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2516
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3283
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3217
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2735
double met_cms_eps[METVAR]
cmultiscale compression epsilon.
Definition: mptrac.h:2714
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2432
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2708
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2438
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3199
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2345
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3172
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3262
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3100
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2762
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3094
int met_lossy_scale[METVAR]
Apply levelwise [0,1] scaling before lossy compression (0=off, 1=on).
Definition: mptrac.h:2693
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3259
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2699
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:3078
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2732
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3247
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2414
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2462
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2477
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2753
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3256
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2435
double turb_pbl_trans
Depth of turbulent PBL transition layer (fraction of PBL pressure thickness).
Definition: mptrac.h:2853
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:3081
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3250
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2666
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:3027
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3115
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2702
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2711
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3187
double met_sz3_tol[METVAR]
SZ3 compression tolerance.
Definition: mptrac.h:2690
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3295
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2363
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2663
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2955
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3304
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2525
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2354
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3112
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2486
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2342
int met_dy
Stride for latitudes.
Definition: mptrac.h:2720
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3320
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2306
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2784
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2402
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2297
int met_zfp_prec[METVAR]
ZFP compression precision.
Definition: mptrac.h:2681
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3271
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3301
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3277
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3223
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3323
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2366
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2411
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2423
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3184
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2528
Here is the call graph for this function:

◆ mptrac_read_met()

int mptrac_read_met ( const char *  filename,
const ctl_t ctl,
const clim_t clim,
met_t met,
dd_t dd 
)

Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.

This function reads meteorological data from a file specified by the filename parameter. It supports both NetCDF and binary formats based on the met_type field in the ctl_t structure. The function can also handle parallel processing with MPI, broadcasting the data across ranks if required by the configuration.

Parameters
filenameA constant character pointer representing the name of the file to read the meteorological data from.
ctlA pointer to a ctl_t structure, which holds control parameters including the type of meteorological data, MPI sharing flags, and configuration details.
climA pointer to a clim_t structure, which contains climatological data to be used in the process, if applicable.
metA pointer to a met_t structure that will store the meteorological data read from the file.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.
Returns
Returns an integer, where 1 indicates success.
Note
  • The function logs the action of reading meteorological data, including the file name.
  • It supports MPI parallelization and will share the data across multiple processes if the met_mpi_share flag is set in the control structure.
  • If ctl->met_type is 0, the data is read from a NetCDF file using the read_met_nc function.
  • If ctl->met_type is between 1 and 5, or equals 7 or 8, the data is read from a binary file using the read_met_bin function.
  • If ctl->met_type is 6, the data is read from grib files using the read_met_grib function.
  • If the met_type is not recognized, an error message is generated.
Author
Lars Hoffmann

Definition at line 7436 of file mptrac.c.

7441 {
7442
7443 /* Write info... */
7444 LOG(1, "Read meteo data: %s", filename);
7445
7446 /* Set rank... */
7447 int rank = 0;
7448#ifdef MPI
7449 if (ctl->met_mpi_share)
7450 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
7451#endif
7452
7453 /* Check rank... */
7454 if (!ctl->met_mpi_share || rank == 0) {
7455
7456 /* Read netCDF data... */
7457 if (ctl->met_type == 0) {
7458 if (read_met_nc(filename, ctl, met, dd) != 1)
7459 return 0;
7460 }
7461
7462 /* Read binary data... */
7463 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
7464 || ctl->met_type == 7 || ctl->met_type == 8) {
7465 if (read_met_bin(filename, ctl, met) != 1)
7466 return 0;
7467 }
7468#ifdef ECCODES
7469 /* Read grib data... */
7470 else if (ctl->met_type == 6) {
7471 if (read_met_grib(filename, ctl, met) != 1)
7472 return 0;
7473 }
7474#endif
7475
7476 /* Not implemented... */
7477 else
7478 ERRMSG("MET_TYPE not implemented!");
7479
7480 /* Preprocessing for netCDF and grib files... */
7481 if (ctl->met_type == 0 || ctl->met_type == 6) {
7482
7483 /* Extrapolate data for lower boundary... */
7485
7486 /* Fix polar winds... */
7488
7489 /* Create periodic boundary conditions... */
7490#ifndef DD
7491 read_met_periodic(met);
7492#endif
7493
7494 /* Downsampling... */
7495 read_met_sample(ctl, met);
7496
7497 /* Calculate geopotential heights... */
7498 read_met_geopot(ctl, met);
7499
7500 /* Calculate potential vorticity... */
7501 read_met_pv(met);
7502
7503 /* Calculate boundary layer data... */
7504 read_met_pbl(ctl, met);
7505
7506 /* Calculate tropopause data... */
7507 read_met_tropo(ctl, clim, met);
7508
7509 /* Calculate cloud properties... */
7510 read_met_cloud(met);
7511
7512 /* Calculate convective available potential energy... */
7513 read_met_cape(ctl, clim, met);
7514
7515 /* Calculate total column ozone... */
7516 read_met_ozone(met);
7517
7518 /* Detrending... */
7519 read_met_detrend(ctl, met);
7520
7521 /* Check meteo data and smooth zeta profiles ... */
7522 read_met_monotonize(ctl, met);
7523 }
7524 }
7525
7526 /* Broadcast data via MPI... */
7527#ifdef MPI
7528 if (ctl->met_mpi_share) {
7529
7530 /* Set timer... */
7531 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM");
7532 LOG(2, "Broadcast data on rank %d...", rank);
7533
7534 /* Broadcast... */
7535 broadcast_large_data(met, sizeof(met_t));
7536 }
7537#endif
7538
7539 /* Return success... */
7540 return 1;
7541}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:9186
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:9146
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:11662
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:8982
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:11253
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:9039
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:10949
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:11390
int read_met_nc(const char *filename, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads meteorological data from a NetCDF file and processes it.
Definition: mptrac.c:11034
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:11633
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:11513
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:8563
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:11451
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:8862
int read_met_grib(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a grib file and processes it.
void broadcast_large_data(void *data, size_t N)
Broadcasts large data across all processes in an MPI communicator.
Here is the call graph for this function:

◆ mptrac_run_timestep()

void mptrac_run_timestep ( ctl_t ctl,
cache_t cache,
clim_t clim,
met_t **  met0,
met_t **  met1,
atm_t atm,
double  t,
dd_t dd 
)

Executes a single timestep of the MPTRAC model simulation.

This function performs all operations required to advance the model simulation by one timestep. It includes updating air parcel positions, applying advection, diffusion, convection, and other processes such as sedimentation, chemistry, and deposition. Each process is conditionally executed based on the control settings provided in the ctl structure.

Parameters
ctlPointer to the control structure containing model parameters and settings.
cachePointer to the cache structure used for intermediate calculations.
climPointer to the climatology structure containing climatological data.
met0Pointer to the current meteorological data structure.
met1Pointer to the next meteorological data structure.
atmPointer to the atmosphere structure containing air parcel data.
tCurrent simulation time in seconds.
ddMPI information required for the domain decomposition.
Author
Lars Hoffmann

Definition at line 7545 of file mptrac.c.

7553 {
7554
7555 /* Initialize modules... */
7556 if (t == ctl->t_start) {
7557
7558 /* Initialize isosurface data... */
7559 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7560 module_isosurf_init(ctl, cache, *met0, *met1, atm);
7561
7562 /* Initialize advection... */
7563 module_advect_init(ctl, cache, *met0, *met1, atm);
7564
7565 /* Initialize chemistry... */
7566 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
7567 }
7568
7569 /* Set time steps of air parcels... */
7570 module_timesteps(ctl, cache, *met0, atm, t);
7571
7572 /* Sort particles... */
7573 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
7574 module_sort(ctl, *met0, atm);
7575
7576 /* Check positions (initial)... */
7577 module_position(cache, *met0, *met1, atm);
7578
7579 /* Advection... */
7580 if (ctl->advect > 0)
7581 module_advect(ctl, cache, *met0, *met1, atm);
7582
7583 /* Turbulent diffusion... */
7584 if (ctl->diffusion
7585 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
7586 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
7587 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
7588 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
7589
7590 /* Optional PBL-specific diffusion scheme... */
7591 if (ctl->diffusion && ctl->turb_pbl_scheme == 1)
7592 module_diff_pbl(ctl, cache, *met0, *met1, atm);
7593
7594 /* Mesoscale diffusion... */
7595 if (ctl->diffusion && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
7596 module_diff_meso(ctl, cache, *met0, *met1, atm);
7597
7598 /* Convection... */
7599 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
7600 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
7601 module_convection(ctl, cache, *met0, *met1, atm);
7602
7603 /* Sedimentation... */
7604 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
7605 module_sedi(ctl, cache, *met0, *met1, atm);
7606
7607 /* Isosurface... */
7608 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7609 module_isosurf(ctl, cache, *met0, *met1, atm);
7610
7611 /* Check positions (final)... */
7612 module_position(cache, *met0, *met1, atm);
7613
7614 /* Interpolate meteo data... */
7615 if (ctl->met_dt_out > 0
7616 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
7617 module_meteo(ctl, cache, clim, *met0, *met1, atm);
7618
7619 /* Check boundary conditions (initial)... */
7620 if ((ctl->bound_lat0 < ctl->bound_lat1)
7621 && (ctl->bound_p0 > ctl->bound_p1))
7622 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
7623
7624 /* Initialize quantity of total loss rate... */
7625 if (ctl->qnt_loss_rate >= 0) {
7626 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
7627 atm->q[ctl->qnt_loss_rate][ip] = 0;
7628 }
7629 }
7630
7631 /* Decay of particle mass... */
7632 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
7633 module_decay(ctl, cache, clim, atm);
7634
7635 /* Interparcel mixing... */
7636 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
7637 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
7638 module_mixing(ctl, clim, atm, t);
7639
7640 /* Calculate the tracer vmr in the chemistry grid... */
7641 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
7642 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
7643 module_chem_grid(ctl, *met0, *met1, atm, t);
7644
7645 /* OH chemistry... */
7646 if (ctl->oh_chem_reaction != 0)
7647 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
7648
7649 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
7650 if (ctl->h2o2_chem_reaction != 0)
7651 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
7652
7653 /* First-order tracer chemistry... */
7654 if (ctl->tracer_chem)
7655 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
7656
7657 /* Radioactive decay... */
7658 if (ctl->radio_decay)
7659 module_radio_decay(ctl, cache, atm);
7660
7661 /* Domain decomposition... */
7662#ifdef DD
7663 module_dd(t, ctl, cache, dd, atm, met0);
7664#else
7665 (void) dd;
7666#endif
7667
7668 /* KPP chemistry... */
7669 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
7670#ifdef KPP
7671 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
7672#else
7673 ERRMSG("Code was compiled without KPP!");
7674#endif
7675 }
7676
7677 /* Wet deposition... */
7678 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
7679 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
7680 module_wet_depo(ctl, cache, *met0, *met1, atm);
7681
7682 /* Dry deposition... */
7683 if (ctl->dry_depo_vdep > 0)
7684 module_dry_depo(ctl, cache, *met0, *met1, atm);
7685
7686 /* Check boundary conditions (final)... */
7687 if ((ctl->bound_lat0 < ctl->bound_lat1)
7688 && (ctl->bound_p0 > ctl->bound_p1))
7689 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
7690}
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:3598
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:5811
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:5054
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:4219
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:4050
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:5161
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:4878
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:5963
void module_chem_grid(const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double tt)
Computes gridded chemical tracer concentrations (volume mixing ratio) from individual air parcel mass...
Definition: mptrac.c:3885
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:5671
void module_sort(const ctl_t *ctl, const met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:5699
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:4094
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:3789
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:3762
void module_radio_decay(const ctl_t *ctl, const cache_t *cache, atm_t *atm)
Apply radioactive decay to atmospheric tracer species.
Definition: mptrac.c:5477
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:5419
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:4258
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:4580
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:5889
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:4793
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:4335
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:4948
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:5335
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:4730
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.
void module_dd(double t, const ctl_t *ctl, cache_t *cache, dd_t *dd, atm_t *atm, met_t **met)
Perform domain decomposition and exchange particles between MPI ranks.
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 7694 of file mptrac.c.

7700 {
7701
7702 /* Update GPU... */
7703 if (ctl != NULL) {
7704#ifdef _OPENACC
7705 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7706#pragma acc update device(ctl[:1])
7707#endif
7708 }
7709
7710 if (cache != NULL) {
7711#ifdef _OPENACC
7712 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7713#pragma acc update device(cache[:1])
7714#endif
7715 }
7716
7717 if (clim != NULL) {
7718#ifdef _OPENACC
7719 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7720#pragma acc update device(clim[:1])
7721#endif
7722 }
7723
7724 if (met0 != NULL) {
7725#ifdef _OPENACC
7726 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7727 met_t *met0up = *met0;
7728#pragma acc update device(met0up[:1])
7729#endif
7730 }
7731
7732 if (met1 != NULL) {
7733#ifdef _OPENACC
7734 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7735 met_t *met1up = *met1;
7736#pragma acc update device(met1up[:1])
7737#endif
7738 }
7739
7740 if (atm != NULL) {
7741#ifdef _OPENACC
7742 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7743#pragma acc update device(atm[:1])
7744#endif
7745 }
7746}

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

7756 {
7757
7758 /* Update GPU... */
7759 if (ctl != NULL) {
7760#ifdef _OPENACC
7761 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7762#pragma acc update host(ctl[:1])
7763#endif
7764 }
7765
7766 if (cache != NULL) {
7767#ifdef _OPENACC
7768 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7769#pragma acc update host(cache[:1])
7770#endif
7771 }
7772
7773 if (clim != NULL) {
7774#ifdef _OPENACC
7775 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7776#pragma acc update host(clim[:1])
7777#endif
7778 }
7779
7780 if (met0 != NULL) {
7781#ifdef _OPENACC
7782 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7783 met_t *met0up = *met0;
7784#pragma acc update host(met0up[:1])
7785#endif
7786 }
7787
7788 if (met1 != NULL) {
7789#ifdef _OPENACC
7790 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7791 met_t *met1up = *met1;
7792#pragma acc update host(met1up[:1])
7793#endif
7794 }
7795
7796 if (atm != NULL) {
7797#ifdef _OPENACC
7798 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7799#pragma acc update host(atm[:1])
7800#endif
7801 }
7802}

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

7810 {
7811
7812 /* Set timer... */
7813 SELECT_TIMER("WRITE_ATM", "OUTPUT");
7814
7815 /* Write info... */
7816 LOG(1, "Write atmospheric data: %s", filename);
7817
7818 /* Write ASCII data... */
7819 if (ctl->atm_type_out == 0)
7820 write_atm_asc(filename, ctl, atm, t);
7821
7822 /* Write binary data... */
7823 else if (ctl->atm_type_out == 1)
7824 write_atm_bin(filename, ctl, atm);
7825
7826 /* Write netCDF data... */
7827 else if (ctl->atm_type_out == 2)
7828 write_atm_nc(filename, ctl, atm);
7829
7830 /* Write CLaMS trajectory data... */
7831 else if (ctl->atm_type_out == 3)
7832 write_atm_clams_traj(filename, ctl, atm, t);
7833
7834 /* Write CLaMS pos data... */
7835 else if (ctl->atm_type_out == 4)
7836 write_atm_clams(filename, ctl, atm);
7837
7838 /* Error... */
7839 else
7840 ERRMSG("Atmospheric data type not supported!");
7841
7842 /* Write info... */
7843 double mini, maxi;
7844 LOG(2, "Number of particles: %d", atm->np);
7845 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
7846 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
7847 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
7848 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
7849 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
7850 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
7851 LOG(2, "%s range: %g ... %g %s",
7852 ctl->met_coord_type == 0 ? "Longitude" : "X coordinate", mini, maxi,
7853 ctl->met_coord_type == 0 ? "deg" : "m");
7854 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
7855 LOG(2, "%s range: %g ... %g %s",
7856 ctl->met_coord_type == 0 ? "Latitude" : "Y coordinate", mini, maxi,
7857 ctl->met_coord_type == 0 ? "deg" : "m");
7858 for (int iq = 0; iq < ctl->nq; iq++) {
7859 char msg[5 * LEN];
7860 sprintf(msg, "Quantity %s range: %s ... %s %s",
7861 ctl->qnt_name[iq], ctl->qnt_format[iq],
7862 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
7863 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
7864 LOG(2, msg, mini, maxi);
7865 }
7866}
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:12654
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:12450
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:12598
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:12548
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:12815
Here is the call graph for this function:

◆ mptrac_write_met()

void mptrac_write_met ( const char *  filename,
const ctl_t ctl,
met_t met 
)

Writes meteorological data to a file, supporting multiple formats and compression options.

This function handles writing meteorological data based on the specified control (ctl_t) and meteorological data (met_t) structures. The file format and compression type are determined by the met_type in the control structure. The function supports netCDF, binary output, and various compression methods (ZFP, ZSTD, CMS), while providing error handling for unsupported configurations.

Parameters
filenameA constant character pointer representing the name of the file to write the meteorological data to.
ctlA pointer to a ctl_t structure, which holds the configuration and control parameters for the output, including the type of meteorological data and compression method.
metA pointer to a met_t structure that holds the meteorological data to be written to the file.
Note
  • The function selects a timer for performance profiling or debugging.
  • It logs the action of writing meteorological data, including the file name.
Warning
  • If ctl->met_type is 3, ZFP compression is required, and the function will generate an error if compiled without ZFP support.
  • If ctl->met_type is 4, ZSTD compression is required, and the function will generate an error if compiled without ZSTD support.
  • If ctl->met_type is 5, CMS compression is required, and the function will generate an error if compiled without CMS support.
  • If ctl->met_type is 7, SZ3 compression is required, and the function will generate an error if compiled without SZ3 support.
  • If ctl->met_type is 8, LZ4 compression is required, and the function will generate an error if compiled without LZ4 support.
Note
  • If ctl->met_type is 0, the function writes data in netCDF format via write_met_nc.
  • If ctl->met_type is between 1 and 5, or equals 7 or 8, the function writes data in binary format via write_met_bin.
  • If ctl->met_type is not recognized, an error message is generated.
Author
Lars Hoffmann

Definition at line 7870 of file mptrac.c.

7873 {
7874
7875 /* Set timer... */
7876 SELECT_TIMER("WRITE_MET", "OUTPUT");
7877
7878 /* Write info... */
7879 LOG(1, "Write meteo data: %s", filename);
7880
7881 /* Check compression flags... */
7882#ifndef ZFP
7883 if (ctl->met_type == 3)
7884 ERRMSG("MPTRAC was compiled without ZFP compression!");
7885#endif
7886#ifndef ZSTD
7887 if (ctl->met_type == 4)
7888 ERRMSG("MPTRAC was compiled without ZSTD compression!");
7889#endif
7890#ifndef LZ4
7891 if (ctl->met_type == 8)
7892 ERRMSG("MPTRAC was compiled without LZ4 compression!");
7893#endif
7894#ifndef CMS
7895 if (ctl->met_type == 5)
7896 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
7897#endif
7898#ifndef SZ3
7899 if (ctl->met_type == 7)
7900 ERRMSG("MPTRAC was compiled without SZ3 compression!");
7901#endif
7902
7903 /* Write netCDF data... */
7904 if (ctl->met_type == 0)
7905 write_met_nc(filename, ctl, met);
7906
7907 /* Write binary data... */
7908 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
7909 || ctl->met_type == 7 || ctl->met_type == 8)
7910 write_met_bin(filename, ctl, met);
7911
7912 /* Not implemented... */
7913 else
7914 ERRMSG("MET_TYPE not implemented!");
7915}
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:13922
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:13670
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 7919 of file mptrac.c.

7925 {
7926
7927 char ext[10], filename[2 * LEN];
7928
7929 double r;
7930
7931 int year, mon, day, hour, min, sec;
7932
7933 /* Get time... */
7934 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
7935
7936 /* Update host... */
7937 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
7938 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
7939 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
7940 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
7941 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
7942 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
7943 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
7944
7945 /* Write atmospheric data... */
7946 if (ctl->atm_basename[0] != '-' &&
7947 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
7948 if (ctl->atm_type_out == 0)
7949 sprintf(ext, "tab");
7950 else if (ctl->atm_type_out == 1)
7951 sprintf(ext, "bin");
7952 else if (ctl->atm_type_out >= 2)
7953 sprintf(ext, "nc");
7954 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
7955 dirname, ctl->atm_basename, year, mon, day, hour, min, sec, ext);
7956 mptrac_write_atm(filename, ctl, atm, t);
7957 }
7958
7959 /* Write gridded data... */
7960 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
7961 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
7962 dirname, ctl->grid_basename, year, mon, day, hour, min, sec,
7963 ctl->grid_type == 0 ? "tab" : "nc");
7964 write_grid(filename, ctl, met0, met1, atm, t);
7965 }
7966
7967 /* Write CSI data... */
7968 if (ctl->csi_basename[0] != '-') {
7969 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
7970 write_csi(filename, ctl, atm, t);
7971 }
7972
7973 /* Write ensemble data... */
7974 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
7975 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.tab",
7976 dirname, ctl->ens_basename, year, mon, day, hour, min, sec);
7977 write_ens(filename, ctl, atm, t);
7978 }
7979
7980 /* Write profile data... */
7981 if (ctl->prof_basename[0] != '-') {
7982 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
7983 write_prof(filename, ctl, met0, met1, atm, t);
7984 }
7985
7986 /* Write sample data... */
7987 if (ctl->sample_basename[0] != '-') {
7988 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
7989 write_sample(filename, ctl, met0, met1, atm, t);
7990 }
7991
7992 /* Write station data... */
7993 if (ctl->stat_basename[0] != '-') {
7994 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
7995 write_station(filename, ctl, atm, t);
7996 }
7997
7998 /* Write VTK data... */
7999 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
8000 static int nvtk;
8001 if (t == ctl->t_start)
8002 nvtk = 0;
8003 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
8004 write_vtk(filename, ctl, atm, t);
8005 }
8006}
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:7806
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:13142
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:14165
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:7750
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:14560
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:14649
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:14395
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:13242
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:12864
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 8010 of file mptrac.c.

8013 {
8014
8015 /* Check water vapor volume mixing ratio... */
8016 const double h2o_help = MAX(h2o, 0.1e-6);
8017
8018 /* Calculate T_NAT... */
8019 const double p_hno3 = hno3 * p / 1.333224;
8020 const double p_h2o = h2o_help * p / 1.333224;
8021 const double a = 0.009179 - 0.00088 * log10(p_h2o);
8022 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
8023 const double c = -11397.0 / a;
8024 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
8025 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
8026 if (x2 > 0)
8027 tnat = x2;
8028
8029 return tnat;
8030}

◆ 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, ps, and TURB_PBL_TRANS, expressed as a fraction of the PBL pressure thickness (ps - pbl).

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

8039 {
8040
8041 /* Get pressure range... */
8042 const double p1 = pbl - ctl->turb_pbl_trans * (ps - pbl);
8043 const double p0 = pbl;
8044
8045 /* Get weighting factor... */
8046 if (atm->p[ip] > p0)
8047 return 1;
8048 else if (atm->p[ip] < p1)
8049 return 0;
8050 else
8051 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
8052}

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

8059 {
8060
8061 /* Open file... */
8062 FILE *in;
8063 if (!(in = fopen(filename, "r"))) {
8064 WARN("Cannot open file!");
8065 return 0;
8066 }
8067
8068 /* Read line... */
8069 char line[LEN];
8070 while (fgets(line, LEN, in)) {
8071
8072 /* Read data... */
8073 char *tok;
8074 TOK(line, tok, "%lg", atm->time[atm->np]);
8075 TOK(NULL, tok, "%lg", atm->p[atm->np]);
8076 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
8077 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
8078 for (int iq = 0; iq < ctl->nq; iq++)
8079 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
8080
8081 /* Convert altitude to pressure... */
8082 atm->p[atm->np] = P(atm->p[atm->np]);
8083
8084 /* Increment data point counter... */
8085 if ((++atm->np) > NP)
8086 ERRMSG("Too many data points!");
8087 }
8088
8089 /* Close file... */
8090 fclose(in);
8091
8092 /* Return success... */
8093 return 1;
8094}
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1964

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

8101 {
8102
8103 /* Open file... */
8104 FILE *in;
8105 if (!(in = fopen(filename, "r")))
8106 return 0;
8107
8108 /* Check version of binary data... */
8109 int version;
8110 FREAD(&version, int,
8111 1,
8112 in);
8113 if (version != 100)
8114 ERRMSG("Wrong version of binary data!");
8115
8116 /* Read data... */
8117 FREAD(&atm->np, int,
8118 1,
8119 in);
8120 FREAD(atm->time, double,
8121 (size_t) atm->np,
8122 in);
8123 FREAD(atm->p, double,
8124 (size_t) atm->np,
8125 in);
8126 FREAD(atm->lon, double,
8127 (size_t) atm->np,
8128 in);
8129 FREAD(atm->lat, double,
8130 (size_t) atm->np,
8131 in);
8132 for (int iq = 0; iq < ctl->nq; iq++)
8133 FREAD(atm->q[iq], double,
8134 (size_t) atm->np,
8135 in);
8136
8137 /* Read final flag... */
8138 int final;
8139 FREAD(&final, int,
8140 1,
8141 in);
8142 if (final != 999)
8143 ERRMSG("Error while reading binary data!");
8144
8145 /* Close file... */
8146 fclose(in);
8147
8148 /* Return success... */
8149 return 1;
8150}

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

8157 {
8158
8159 if (ctl->met_coord_type != 0)
8160 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
8161
8162 int ncid, varid;
8163
8164 /* Open file... */
8165 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8166 return 0;
8167
8168 /* Get dimensions... */
8169 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
8170
8171 /* Get time... */
8172 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
8173 NC(nc_get_var_double(ncid, varid, atm->time));
8174 } else {
8175 WARN("TIME_INIT not found use time instead!");
8176 double time_init;
8177 NC_GET_DOUBLE("time", &time_init, 1);
8178 for (int ip = 0; ip < atm->np; ip++) {
8179 atm->time[ip] = time_init;
8180 }
8181 }
8182
8183 /* Read zeta coordinate, pressure is optional... */
8184 if (ctl->advect_vert_coord == 1) {
8185 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
8186 NC_GET_DOUBLE("PRESS", atm->p, 0);
8187 }
8188
8189 /* Read pressure, zeta coordinate is optional... */
8190 else {
8191 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
8192 NC(nc_get_var_double(ncid, varid, atm->p));
8193 } else {
8194 WARN("PRESS_INIT not found use PRESS instead!");
8195 nc_inq_varid(ncid, "PRESS", &varid);
8196 NC(nc_get_var_double(ncid, varid, atm->p));
8197 }
8198 }
8199
8200 /* Read further quantities if requested... */
8201 for (int iq = 0; iq < ctl->nq; iq++)
8202 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8203
8204 /* Read longitude and latitude... */
8205 NC_GET_DOUBLE("LON", atm->lon, 1);
8206 NC_GET_DOUBLE("LAT", atm->lat, 1);
8207
8208 /* Close file... */
8209 NC(nc_close(ncid));
8210
8211 /* Return success... */
8212 return 1;
8213}
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1298
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1357
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1387

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

8220 {
8221
8222 int ncid, varid;
8223
8224 /* Open file... */
8225 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8226 return 0;
8227
8228 /* Get dimensions... */
8229 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
8230
8231 /* Read geolocations... */
8232 NC_GET_DOUBLE("time", atm->time, 1);
8233 NC_GET_DOUBLE("press", atm->p, 1);
8234 NC_GET_DOUBLE("lon", atm->lon, 1);
8235 NC_GET_DOUBLE("lat", atm->lat, 1);
8236
8237 /* Read variables... */
8238 for (int iq = 0; iq < ctl->nq; iq++)
8239 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8240
8241 /* Close file... */
8242 NC(nc_close(ncid));
8243
8244 /* Return success... */
8245 return 1;
8246}

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

8252 {
8253
8254 int ncid, varid;
8255
8256 /* Write info... */
8257 LOG(1, "Read photolysis rates: %s", filename);
8258
8259 /* Open netCDF file... */
8260 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8261 WARN("Photolysis rate data are missing!");
8262 return;
8263 }
8264
8265 /* Read pressure data... */
8266 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
8267 NC_GET_DOUBLE("press", photo->p, 1);
8268 if (photo->p[0] < photo->p[1])
8269 ERRMSG("Pressure data are not descending!");
8270
8271 /* Read total column ozone data... */
8272 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
8273 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
8274 if (photo->o3c[0] > photo->o3c[1])
8275 ERRMSG("Total column ozone data are not ascending!");
8276
8277 /* Read solar zenith angle data... */
8278 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
8279 NC_GET_DOUBLE("sza", photo->sza, 1);
8280 if (photo->sza[0] > photo->sza[1])
8281 ERRMSG("Solar zenith angle data are not ascending!");
8282
8283 /* Read data... */
8284 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
8285 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
8286 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
8287 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
8288 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
8289 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
8290 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
8291 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
8292 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
8293
8294 /* Close netCDF file... */
8295 NC(nc_close(ncid));
8296
8297 /* Write info... */
8298 LOG(2, "Number of pressure levels: %d", photo->np);
8299 LOG(2, "Altitude levels: %g, %g ... %g km",
8300 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
8301 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8302 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
8303 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
8304 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
8305 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
8306 RAD2DEG(photo->sza[photo->nsza - 1]));
8307 LOG(2, "Number of total column ozone values: %d", photo->no3c);
8308 LOG(2, "Total column ozone: %g, %g ... %g DU",
8309 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
8310 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
8311 photo->n2o[0][0][0], photo->n2o[1][0][0],
8312 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8313 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
8314 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
8315 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8316 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
8317 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
8318 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8319 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
8320 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
8321 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8322 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
8323 photo->o2[0][0][0], photo->o2[1][0][0],
8324 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8325 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
8326 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
8327 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8328 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
8329 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
8330 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8331 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
8332 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
8333 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8334 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
8335 photo->h2o[0][0][0], photo->h2o[1][0][0],
8336 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8337}
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:8341
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:399
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:394
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:404
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3464
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3461
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3470
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3473
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3467
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 8341 of file mptrac.c.

8345 {
8346
8347 /* Allocate... */
8348 double *help;
8349 ALLOC(help, double,
8350 photo->np * photo->nsza * photo->no3c);
8351
8352 /* Read varible... */
8353 int varid;
8354 NC_GET_DOUBLE(varname, help, 1);
8355
8356 /* Copy data... */
8357 for (int ip = 0; ip < photo->np; ip++)
8358 for (int is = 0; is < photo->nsza; is++)
8359 for (int io = 0; io < photo->no3c; io++)
8360 var[ip][is][io] =
8361 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
8362
8363 /* Free... */
8364 free(help);
8365}

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

8371 {
8372
8373 /* Write info... */
8374 LOG(1, "Read climatological time series: %s", filename);
8375
8376 /* Open file... */
8377 FILE *in;
8378 if (!(in = fopen(filename, "r"))) {
8379 WARN("Cannot open file!");
8380 return 0;
8381 }
8382
8383 /* Read data... */
8384 char line[LEN];
8385 int nh = 0;
8386 while (fgets(line, LEN, in))
8387 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
8388
8389 /* Convert years to seconds... */
8390 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
8391
8392 /* Check data... */
8393 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
8394 ERRMSG("Time series must be ascending!");
8395
8396 /* Count time steps... */
8397 if ((++nh) >= CTS)
8398 ERRMSG("Too many data points!");
8399 }
8400
8401 /* Close file... */
8402 fclose(in);
8403
8404 /* Check number of data points... */
8405 ts->ntime = nh;
8406 if (nh < 2)
8407 ERRMSG("Not enough data points!");
8408
8409 /* Write info... */
8410 LOG(2, "Number of time steps: %d", ts->ntime);
8411 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
8412 ts->time[nh - 1]);
8413 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
8414 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
8415 (size_t) nh));
8416
8417 /* Exit success... */
8418 return 1;
8419}
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:414

◆ read_clim_zm()

void read_clim_zm ( const char *  filename,
const char *  varname,
clim_zm_t zm 
)

Reads zonally averaged climatological data from a netCDF file and populates the given structure.

This function reads data from a specified netCDF file, including pressure levels, latitudes, and volume mixing ratios (VMR) for a specified variable. It performs necessary checks and logs detailed information about the loaded data.

Parameters
filenameA string containing the path to the netCDF file.
varnameA string containing the name of the variable to be read from the netCDF file.
zmA pointer to the structure (clim_zm_t) that will be populated with the data.

The function performs the following steps:

  • Logs the initiation of reading the specified data.
  • Opens the netCDF file for reading.
  • Reads pressure level data and checks for descending order.
  • Reads latitude data and checks for ascending order.
  • Sets the time data for monthly means.
  • Checks the number of time steps.
  • Reads the specified variable data from the file.
  • Fixes any gaps in the data by interpolating from valid values.
  • Logs detailed information about the loaded data, including the number of time steps, pressure levels, latitude values, and the range of the variable's volume mixing ratios.
Author
Lars Hoffmann

Definition at line 8423 of file mptrac.c.

8426 {
8427
8428 int ncid, varid, it, iy, iz, iz2, nt;
8429
8430 double *help, varmin = 1e99, varmax = -1e99;
8431
8432 /* Write info... */
8433 LOG(1, "Read %s data: %s", varname, filename);
8434
8435 /* Open netCDF file... */
8436 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8437 WARN("%s climatology data are missing!", varname);
8438 return;
8439 }
8440
8441 /* Read pressure data... */
8442 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
8443 NC_GET_DOUBLE("press", zm->p, 1);
8444 if (zm->p[0] < zm->p[1])
8445 ERRMSG("Pressure data are not descending!");
8446
8447 /* Read latitudes... */
8448 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
8449 NC_GET_DOUBLE("lat", zm->lat, 1);
8450 if (zm->lat[0] > zm->lat[1])
8451 ERRMSG("Latitude data are not ascending!");
8452
8453 /* Set time data (for monthly means)... */
8454 zm->ntime = 12;
8455 zm->time[0] = 1209600.00;
8456 zm->time[1] = 3888000.00;
8457 zm->time[2] = 6393600.00;
8458 zm->time[3] = 9072000.00;
8459 zm->time[4] = 11664000.00;
8460 zm->time[5] = 14342400.00;
8461 zm->time[6] = 16934400.00;
8462 zm->time[7] = 19612800.00;
8463 zm->time[8] = 22291200.00;
8464 zm->time[9] = 24883200.00;
8465 zm->time[10] = 27561600.00;
8466 zm->time[11] = 30153600.00;
8467
8468 /* Check number of timesteps... */
8469 NC_INQ_DIM("time", &nt, 12, 12, 1);
8470
8471 /* Read data... */
8472 ALLOC(help, double,
8473 zm->nlat * zm->np * zm->ntime);
8474 NC_GET_DOUBLE(varname, help, 1);
8475 for (it = 0; it < zm->ntime; it++)
8476 for (iz = 0; iz < zm->np; iz++)
8477 for (iy = 0; iy < zm->nlat; iy++)
8478 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
8479 free(help);
8480
8481 /* Fix data gaps... */
8482 for (it = 0; it < zm->ntime; it++)
8483 for (iy = 0; iy < zm->nlat; iy++)
8484 for (iz = 0; iz < zm->np; iz++) {
8485 if (zm->vmr[it][iz][iy] < 0) {
8486 for (iz2 = 0; iz2 < zm->np; iz2++)
8487 if (zm->vmr[it][iz2][iy] >= 0) {
8488 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8489 break;
8490 }
8491 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
8492 if (zm->vmr[it][iz2][iy] >= 0) {
8493 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8494 break;
8495 }
8496 }
8497 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
8498 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
8499 }
8500
8501 /* Close netCDF file... */
8502 NC(nc_close(ncid));
8503
8504 /* Write info... */
8505 LOG(2, "Number of time steps: %d", zm->ntime);
8506 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
8507 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
8508 LOG(2, "Number of pressure levels: %d", zm->np);
8509 LOG(2, "Altitude levels: %g, %g ... %g km",
8510 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
8511 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
8512 zm->p[1], zm->p[zm->np - 1]);
8513 LOG(2, "Number of latitudes: %d", zm->nlat);
8514 LOG(2, "Latitudes: %g, %g ... %g deg",
8515 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
8516 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
8517 varmax);
8518}
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:389

◆ read_kernel()

void read_kernel ( const char *  filename,
double  kz[EP],
double  kw[EP],
int *  nk 
)

Reads kernel function data from a file and populates the provided arrays.

This function reads kernel function data from a specified file, populating the provided arrays kz and kw with the parsed data. It also updates the variable pointed to by nk with the number of data points read. The function ensures that the height levels are in ascending order and performs checks for the number of height levels read.

Parameters
filenameA string containing the path to the file containing kernel function data.
kzA double array to store the height levels of the kernel function.
kwA double array to store the weights corresponding to the height levels.
nkA pointer to an integer variable representing the number of data points read.

The function performs the following steps:

  • Logs information indicating the kernel function file being read.
  • Attempts to open the specified file for reading.
  • Reads data from the file line by line, parsing height levels and weights.
  • Checks that the height levels are in ascending order and that the number of data points does not exceed the defined maximum.
  • Closes the file after reading.
  • Updates the value of nk with the number of data points read.
  • Normalizes the kernel function weights by dividing each weight by the maximum weight.
Author
Lars Hoffmann

Definition at line 8522 of file mptrac.c.

8526 {
8527
8528 /* Write info... */
8529 LOG(1, "Read kernel function: %s", filename);
8530
8531 /* Open file... */
8532 FILE *in;
8533 if (!(in = fopen(filename, "r")))
8534 ERRMSG("Cannot open file!");
8535
8536 /* Read data... */
8537 char line[LEN];
8538 int n = 0;
8539 while (fgets(line, LEN, in))
8540 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
8541 if (n > 0 && kz[n] < kz[n - 1])
8542 ERRMSG("Height levels must be ascending!");
8543 if ((++n) >= EP)
8544 ERRMSG("Too many height levels!");
8545 }
8546
8547 /* Close file... */
8548 fclose(in);
8549
8550 /* Check number of data points... */
8551 *nk = n;
8552 if (n < 2)
8553 ERRMSG("Not enough height levels!");
8554
8555 /* Normalize kernel function... */
8556 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
8557 for (int iz = 0; iz < n; iz++)
8558 kw[iz] /= kmax;
8559}

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

8566 {
8567
8568 FILE *in;
8569
8570 double r;
8571
8572 int year, mon, day, hour, min, sec;
8573
8574 /* Set timer... */
8575 SELECT_TIMER("READ_MET_BIN", "INPUT");
8576
8577 /* Open file... */
8578 if (!(in = fopen(filename, "r"))) {
8579 WARN("Cannot open file!");
8580 return 0;
8581 }
8582
8583 /* Check type of binary data... */
8584 int met_type;
8585 FREAD(&met_type, int,
8586 1,
8587 in);
8588 if (met_type != ctl->met_type)
8589 ERRMSG("Wrong MET_TYPE of binary data!");
8590
8591 /* Check version of binary data... */
8592 int version;
8593 FREAD(&version, int,
8594 1,
8595 in);
8596 if (version != 104)
8597 ERRMSG("Wrong version of binary data!");
8598
8599 /* Read time... */
8600 FREAD(&met->time, double,
8601 1,
8602 in);
8603 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8604 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8605 met->time, year, mon, day, hour, min);
8606 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8607 || day < 1 || day > 31 || hour < 0 || hour > 23)
8608 ERRMSG("Error while reading time!");
8609
8610 /* Read dimensions... */
8611 met->coord_type = ctl->met_coord_type;
8612
8613 FREAD(&met->nx, int,
8614 1,
8615 in);
8616 LOG(2, "Number of %s: %d",
8617 (met->coord_type == 0) ? "longitudes" : "x coordinates", met->nx);
8618 if (met->nx < 2 || met->nx > EX)
8619 ERRMSG(met->coord_type == 0
8620 ? "Number of longitudes out of range!"
8621 : "Number of x coordinates out of range!");
8622
8623 FREAD(&met->ny, int,
8624 1,
8625 in);
8626 LOG(2, "Number of %s: %d",
8627 (met->coord_type == 0) ? "latitudes" : "y coordinates", met->ny);
8628 if (met->ny < 2 || met->ny > EY)
8629 ERRMSG(met->coord_type == 0
8630 ? "Number of latitudes out of range!"
8631 : "Number of y coordinates out of range!");
8632
8633 FREAD(&met->np, int,
8634 1,
8635 in);
8636 LOG(2, "Number of levels: %d", met->np);
8637 if (met->np < 2 || met->np > EP)
8638 ERRMSG("Number of levels out of range!");
8639
8640 /* Read grid... */
8641 FREAD(met->lon, double,
8642 (size_t) met->nx,
8643 in);
8644 LOG(2, "%s: %g, %g ... %g %s",
8645 met->coord_type == 0 ? "Longitudes" : "X coordinates",
8646 met->lon[0], met->lon[1], met->lon[met->nx - 1],
8647 met->coord_type == 0 ? "deg" : "m");
8648
8649 FREAD(met->lat, double,
8650 (size_t) met->ny,
8651 in);
8652 LOG(2, "%s: %g, %g ... %g %s",
8653 met->coord_type == 0 ? "Latitudes" : "Y coordinates",
8654 met->lat[0], met->lat[1], met->lat[met->ny - 1],
8655 met->coord_type == 0 ? "deg" : "m");
8656
8657 FREAD(met->p, double,
8658 (size_t) met->np,
8659 in);
8660 LOG(2, "Altitude levels: %g, %g ... %g km",
8661 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8662 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8663 met->p[0], met->p[1], met->p[met->np - 1]);
8664
8665 /* Read surface data... */
8666 read_met_bin_2d(in, met, met->ps, "PS");
8667 read_met_bin_2d(in, met, met->ts, "TS");
8668 read_met_bin_2d(in, met, met->zs, "ZS");
8669 read_met_bin_2d(in, met, met->us, "US");
8670 read_met_bin_2d(in, met, met->vs, "VS");
8671 read_met_bin_2d(in, met, met->ess, "ESS");
8672 read_met_bin_2d(in, met, met->nss, "NSS");
8673 read_met_bin_2d(in, met, met->shf, "SHF");
8674 read_met_bin_2d(in, met, met->lsm, "LSM");
8675 read_met_bin_2d(in, met, met->sst, "SST");
8676 read_met_bin_2d(in, met, met->pbl, "PBL");
8677 read_met_bin_2d(in, met, met->pt, "PT");
8678 read_met_bin_2d(in, met, met->tt, "TT");
8679 read_met_bin_2d(in, met, met->zt, "ZT");
8680 read_met_bin_2d(in, met, met->h2ot, "H2OT");
8681 read_met_bin_2d(in, met, met->pct, "PCT");
8682 read_met_bin_2d(in, met, met->pcb, "PCB");
8683 read_met_bin_2d(in, met, met->cl, "CL");
8684 read_met_bin_2d(in, met, met->plcl, "PLCL");
8685 read_met_bin_2d(in, met, met->plfc, "PLFC");
8686 read_met_bin_2d(in, met, met->pel, "PEL");
8687 read_met_bin_2d(in, met, met->cape, "CAPE");
8688 read_met_bin_2d(in, met, met->cin, "CIN");
8689 read_met_bin_2d(in, met, met->o3c, "O3C");
8690
8691 /* Read level data... */
8692 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
8693 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
8694 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
8695 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
8696 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
8697 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
8698 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
8699 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
8700 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
8701 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
8702 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
8703 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
8704 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
8705
8706 /* Read final flag... */
8707 int final;
8708 FREAD(&final, int,
8709 1,
8710 in);
8711 if (final != 999)
8712 ERRMSG("Error while reading binary data!");
8713
8714 /* Close file... */
8715 fclose(in);
8716
8717 /* Return success... */
8718 return 1;
8719}
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:8723
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:8752
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:344
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3676
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3664
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3736
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3706
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3700
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3682
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3658
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3733
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3646
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3745
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3640
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3652
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3685
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3697
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3703
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3691
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3673
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3667
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3649
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3661
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3739
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3679
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3724
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3688
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3655
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3694
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3742
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 8723 of file mptrac.c.

8727 {
8728
8729 float *help;
8730
8731 /* Allocate... */
8732 ALLOC(help, float,
8733 EX * EY);
8734
8735 /* Read uncompressed... */
8736 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
8737 FREAD(help, float,
8738 (size_t) (met->nx * met->ny),
8739 in);
8740
8741 /* Copy data... */
8742 for (int ix = 0; ix < met->nx; ix++)
8743 for (int iy = 0; iy < met->ny; iy++)
8744 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
8745
8746 /* Free... */
8747 free(help);
8748}
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:480

◆ read_met_bin_3d()

void read_met_bin_3d ( FILE *  in,
const ctl_t ctl,
const met_t met,
float  var[EX][EY][EP],
const char *  varname,
const float  bound_min,
const float  bound_max 
)

Reads 3D meteorological data from a binary file, potentially using different compression methods.

This function reads 3-dimensional meteorological data from a binary file into a specified variable array. The data can be read in uncompressed form or using one of several supported compression methods. The data is then clamped to specified minimum and maximum bounds.

Parameters
[in]inPointer to the input file from which to read the data.
[in]ctlPointer to the control structure that contains metadata about the type of data and how it is stored.
[in]metPointer to the meteorological structure that contains the dimensions of the data.
[out]var3D array to store the read data, with dimensions [EX][EY][EP].
[in]varnameName of the variable being read, used for logging and debugging.
[in]bound_minMinimum bound to which data values should be clamped.
[in]bound_maxMaximum bound to which data values should be clamped.

The function supports the following types of data:

  • Uncompressed data
  • Packed data
  • ZFP compressed data (if compiled with ZFP support)
  • ZSTD compressed data (if compiled with ZSTD support)
  • cmultiscale compressed data (if compiled with CMS support)

Depending on the compression type specified in the control structure, the appropriate reading and decompression function is used. The data is read into a temporary buffer, then copied into the output array, applying the specified bounds to each value.

Note
The function assumes that the dimensions EX, EY, and EP are correctly defined and match the dimensions specified in the met structure.
If the appropriate compression support is not compiled, an error message is generated.
Author
Lars Hoffmann

Definition at line 8752 of file mptrac.c.

8759 {
8760
8761 float *help;
8762
8763 /* Allocate... */
8764 ALLOC(help, float,
8765 EX * EY * EP);
8766
8767 /* Read uncompressed data... */
8768 if (ctl->met_type == 1) {
8769 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
8770 FREAD(help, float,
8771 (size_t) (met->nx * met->ny * met->np),
8772 in);
8773 }
8774
8775 /* Read packed data... */
8776 else if (ctl->met_type == 2)
8777 compress_pck(ctl, met, varname, help, 1, NULL, in);
8778
8779 /* Read ZFP data... */
8780 else if (ctl->met_type == 3) {
8781#ifdef ZFP
8782 int precision;
8783 FREAD(&precision, int,
8784 1,
8785 in);
8786
8787 double tolerance;
8788 FREAD(&tolerance, double,
8789 1,
8790 in);
8791
8792 compress_zfp(ctl, met, varname, help, 1, NULL, in);
8793#else
8794 ERRMSG("MPTRAC was compiled without ZFP compression!");
8795#endif
8796 }
8797
8798 /* Read zstd data... */
8799 else if (ctl->met_type == 4) {
8800#ifdef ZSTD
8801 compress_zstd(ctl, met, varname, help, 1, NULL, in);
8802#else
8803 ERRMSG("MPTRAC was compiled without ZSTD compression!");
8804#endif
8805 }
8806
8807 /* Read LZ4 data... */
8808 else if (ctl->met_type == 8) {
8809#ifdef LZ4
8810 compress_lz4(ctl, met, varname, help, 1, NULL, in);
8811#else
8812 ERRMSG("MPTRAC was compiled without LZ4 compression!");
8813#endif
8814 }
8815
8816 /* Read cmultiscale data... */
8817 else if (ctl->met_type == 5) {
8818#ifdef CMS
8819 compress_cms(ctl, met, varname, help, 1, NULL, in);
8820#else
8821 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
8822#endif
8823 }
8824
8825 /* Read SZ3 data... */
8826 else if (ctl->met_type == 7) {
8827#ifdef SZ3
8828 int precision;
8829 FREAD(&precision, int,
8830 1,
8831 in);
8832
8833 double tolerance;
8834 FREAD(&tolerance, double,
8835 1,
8836 in);
8837
8838 compress_sz3(ctl, met, varname, help, 1, NULL, in);
8839#else
8840 ERRMSG("MPTRAC was compiled without sz3 compression!");
8841#endif
8842 }
8843
8844 /* Copy data... */
8845#pragma omp parallel for default(shared) collapse(2)
8846 for (int ix = 0; ix < met->nx; ix++)
8847 for (int iy = 0; iy < met->ny; iy++)
8848 for (int ip = 0; ip < met->np; ip++) {
8849 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
8850 if (var[ix][iy][ip] < bound_min)
8851 var[ix][iy][ip] = bound_min;
8852 else if (var[ix][iy][ip] > bound_max)
8853 var[ix][iy][ip] = bound_max;
8854 }
8855
8856 /* Free... */
8857 free(help);
8858}
void compress_pck(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3‑D float array using the PCK format.
Definition: mptrac.c:986
void compress_zfp(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
void compress_sz3(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3-D float array using the SZ3 library.
void compress_zstd(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a float array using ZSTD.
void compress_cms(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3-D meteorological field using cmultiscale.
void compress_lz4(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a float array using LZ4.
Here is the call graph for this function:

◆ read_met_cape()

void read_met_cape ( const ctl_t ctl,
const clim_t clim,
met_t met 
)

Calculates Convective Available Potential Energy (CAPE) for each grid point.

This function calculates the Convective Available Potential Energy (CAPE) at each grid point based on the provided meteorological data. CAPE is a measure of the energy available for deep convection, which is essential for severe weather development.

Parameters
ctlPointer to the control structure that contains metadata about the type of data and how it is stored.
climA pointer to a structure containing climatological data.
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the calculation time.
  • Initializes variables and constants required for the computation, such as vertical spacing and pressure levels.
  • Iterates over each grid point in parallel using OpenMP.
  • Calculates CAPE by integrating the difference in virtual temperatures between the environment and the parcel, up to the level of free convection (LFC).
  • Determines the lifted condensation level (LCL), level of free convection (LFC), equilibrium level (EL), and Convective Inhibition (CIN) for each grid point.
  • Checks the results and updates the corresponding fields in the meteorological data structure.
Note
The function utilizes OpenMP for parallelization to enhance performance by distributing the computation across multiple threads.
Author
Lars Hoffmann

Definition at line 8862 of file mptrac.c.

8865 {
8866
8867 /* Check parameters... */
8868 if (ctl->met_cape != 1)
8869 return;
8870
8871 if (ctl->met_coord_type != 0)
8872 ERRMSG("Only lat/lon grid supported");
8873
8874 /* Set timer... */
8875 SELECT_TIMER("READ_MET_CAPE", "METPROC");
8876 LOG(2, "Calculate CAPE...");
8877
8878 /* Vertical spacing (about 100 m)... */
8879 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
8880
8881 /* Loop over columns... */
8882#pragma omp parallel for default(shared) collapse(2)
8883 for (int ix = 0; ix < met->nx; ix++)
8884 for (int iy = 0; iy < met->ny; iy++) {
8885
8886 /* Get potential temperature and water vapor at lowest 50 hPa... */
8887 int n = 0;
8888 double h2o = 0, t, theta = 0;
8889 double pbot = MIN(met->ps[ix][iy], met->p[0]);
8890 double ptop = pbot - 50.;
8891 for (int ip = 0; ip < met->np; ip++) {
8892 if (met->p[ip] <= pbot) {
8893 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
8894 h2o += met->h2o[ix][iy][ip];
8895 n++;
8896 }
8897 if (met->p[ip] < ptop && n > 0)
8898 break;
8899 }
8900 theta /= n;
8901 h2o /= n;
8902
8903 /* Cannot compute anything if water vapor is missing... */
8904 met->plcl[ix][iy] = NAN;
8905 met->plfc[ix][iy] = NAN;
8906 met->pel[ix][iy] = NAN;
8907 met->cape[ix][iy] = NAN;
8908 met->cin[ix][iy] = NAN;
8909 if (h2o <= 0)
8910 continue;
8911
8912 /* Find lifted condensation level (LCL)... */
8913 ptop = P(20.);
8914 pbot = met->ps[ix][iy];
8915 do {
8916 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
8917 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
8918 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
8919 ptop = met->plcl[ix][iy];
8920 else
8921 pbot = met->plcl[ix][iy];
8922 } while (pbot - ptop > 0.1);
8923
8924 /* Calculate CIN up to LCL... */
8926 double dcape, dz, h2o_env, t_env;
8927 double p = met->ps[ix][iy];
8928 met->cape[ix][iy] = met->cin[ix][iy] = 0;
8929 do {
8930 dz = dz0 * TVIRT(t, h2o);
8931 p /= pfac;
8932 t = theta / pow(1000. / p, 0.286);
8933 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
8934 &t_env, ci, cw, 1);
8935 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
8936 &h2o_env, ci, cw, 0);
8937 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
8938 TVIRT(t_env, h2o_env) * dz;
8939 if (dcape < 0)
8940 met->cin[ix][iy] += fabsf((float) dcape);
8941 } while (p > met->plcl[ix][iy]);
8942
8943 /* Calculate level of free convection (LFC), equilibrium level (EL),
8944 and convective available potential energy (CAPE)... */
8945 dcape = 0;
8946 p = met->plcl[ix][iy];
8947 t = theta / pow(1000. / p, 0.286);
8948 ptop = 0.75 * clim_tropo(clim, met->time,
8949 ctl->met_coord_type ==
8950 0 ? met->lat[iy] : ctl->met_utm_ref_lat);
8951 do {
8952 dz = dz0 * TVIRT(t, h2o);
8953 p /= pfac;
8954 t -= lapse_rate(t, h2o) * dz;
8955 double psat = PSAT(t);
8956 h2o = psat / (p - (1. - EPS) * psat);
8957 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
8958 &t_env, ci, cw, 1);
8959 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
8960 &h2o_env, ci, cw, 0);
8961 double dcape_old = dcape;
8962 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
8963 TVIRT(t_env, h2o_env) * dz;
8964 if (dcape > 0) {
8965 met->cape[ix][iy] += (float) dcape;
8966 if (!isfinite(met->plfc[ix][iy]))
8967 met->plfc[ix][iy] = (float) p;
8968 } else if (dcape_old > 0)
8969 met->pel[ix][iy] = (float) p;
8970 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
8971 met->cin[ix][iy] += fabsf((float) dcape);
8972 } while (p > ptop);
8973
8974 /* Check results... */
8975 if (!isfinite(met->plfc[ix][iy]))
8976 met->cin[ix][iy] = NAN;
8977 }
8978}
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:213
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 8982 of file mptrac.c.

8983 {
8984
8985 /* Set timer... */
8986 SELECT_TIMER("READ_MET_CLOUD", "METPROC");
8987 LOG(2, "Calculate cloud data...");
8988
8989 /* Thresholds for cloud detection... */
8990 const double ccmin = 0.01, cwmin = 1e-6;
8991
8992 /* Loop over columns... */
8993#pragma omp parallel for default(shared) collapse(2)
8994 for (int ix = 0; ix < met->nx; ix++)
8995 for (int iy = 0; iy < met->ny; iy++) {
8996
8997 /* Init... */
8998 met->pct[ix][iy] = NAN;
8999 met->pcb[ix][iy] = NAN;
9000 met->cl[ix][iy] = 0;
9001
9002 /* Loop over pressure levels... */
9003 for (int ip = 0; ip < met->np - 1; ip++) {
9004
9005 /* Check pressure... */
9006 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
9007 continue;
9008
9009 /* Check ice water and liquid water content... */
9010 if (met->cc[ix][iy][ip] > ccmin
9011 && (met->lwc[ix][iy][ip] > cwmin
9012 || met->rwc[ix][iy][ip] > cwmin
9013 || met->iwc[ix][iy][ip] > cwmin
9014 || met->swc[ix][iy][ip] > cwmin)) {
9015
9016 /* Get cloud top pressure ... */
9017 met->pct[ix][iy]
9018 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
9019
9020 /* Get cloud bottom pressure ... */
9021 if (!isfinite(met->pcb[ix][iy]))
9022 met->pcb[ix][iy]
9023 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
9024 }
9025
9026 /* Get cloud water... */
9027 met->cl[ix][iy] += (float)
9028 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
9029 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
9030 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
9031 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
9032 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
9033 }
9034 }
9035}

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

9041 {
9042
9043 met_t *help;
9044
9045 /* Check parameters... */
9046 if (ctl->met_detrend <= 0)
9047 return;
9048
9049 if (ctl->met_coord_type != 0)
9050 ERRMSG("Only lat/lon grid supported");
9051
9052 /* Set timer... */
9053 SELECT_TIMER("READ_MET_DETREND", "METPROC");
9054 LOG(2, "Detrend meteo data...");
9055
9056 /* Allocate... */
9057 ALLOC(help, met_t, 1);
9058
9059 /* Calculate standard deviation... */
9060 const double sigma = ctl->met_detrend / 2.355;
9061 const double tssq = 2. * SQR(sigma);
9062
9063 /* Calculate box size in latitude... */
9064 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
9065 sy = MIN(MAX(1, sy), met->ny / 2);
9066
9067 /* Calculate background... */
9068#pragma omp parallel for default(shared) collapse(2)
9069 for (int ix = 0; ix < met->nx; ix++) {
9070 for (int iy = 0; iy < met->ny; iy++) {
9071
9072 /* Calculate Cartesian coordinates... */
9073 double x0[3];
9074 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
9075
9076 /* Calculate box size in longitude... */
9077 int sx =
9078 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
9079 fabs(met->lon[1] - met->lon[0]));
9080 sx = MIN(MAX(1, sx), met->nx / 2);
9081
9082 /* Init... */
9083 float wsum = 0;
9084 for (int ip = 0; ip < met->np; ip++) {
9085 help->t[ix][iy][ip] = 0;
9086 help->u[ix][iy][ip] = 0;
9087 help->v[ix][iy][ip] = 0;
9088 help->w[ix][iy][ip] = 0;
9089 }
9090
9091 /* Loop over neighboring grid points... */
9092 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
9093 int ix3 = ix2;
9094 if (ix3 < 0)
9095 ix3 += met->nx;
9096 else if (ix3 >= met->nx)
9097 ix3 -= met->nx;
9098 for (int iy2 = MAX(iy - sy, 0);
9099 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
9100
9101 /* Calculate Cartesian coordinates... */
9102 double x1[3];
9103 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
9104
9105 /* Calculate weighting factor... */
9106 const float w = (float) exp(-DIST2(x0, x1) / tssq);
9107
9108 /* Add data... */
9109 wsum += w;
9110 for (int ip = 0; ip < met->np; ip++) {
9111 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
9112 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
9113 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
9114 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
9115 }
9116 }
9117 }
9118
9119 /* Normalize... */
9120 for (int ip = 0; ip < met->np; ip++) {
9121 help->t[ix][iy][ip] /= wsum;
9122 help->u[ix][iy][ip] /= wsum;
9123 help->v[ix][iy][ip] /= wsum;
9124 help->w[ix][iy][ip] /= wsum;
9125 }
9126 }
9127 }
9128
9129 /* Subtract background... */
9130#pragma omp parallel for default(shared) collapse(3)
9131 for (int ix = 0; ix < met->nx; ix++)
9132 for (int iy = 0; iy < met->ny; iy++)
9133 for (int ip = 0; ip < met->np; ip++) {
9134 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
9135 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
9136 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
9137 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
9138 }
9139
9140 /* Free... */
9141 free(help);
9142}
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:2601
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:694
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:810
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:712
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 9146 of file mptrac.c.

9147 {
9148
9149 /* Set timer... */
9150 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC");
9151 LOG(2, "Extrapolate meteo data...");
9152
9153 /* Loop over columns... */
9154#pragma omp parallel for default(shared) collapse(2)
9155 for (int ix = 0; ix < met->nx; ix++)
9156 for (int iy = 0; iy < met->ny; iy++) {
9157
9158 /* Find lowest valid data point... */
9159 int ip0;
9160 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
9161 if (!isfinite(met->t[ix][iy][ip0])
9162 || !isfinite(met->u[ix][iy][ip0])
9163 || !isfinite(met->v[ix][iy][ip0])
9164 || !isfinite(met->w[ix][iy][ip0]))
9165 break;
9166
9167 /* Extrapolate... */
9168 for (int ip = ip0; ip >= 0; ip--) {
9169 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
9170 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
9171 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
9172 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
9173 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
9174 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
9175 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
9176 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
9177 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
9178 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
9179 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
9180 }
9181 }
9182}

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

9188 {
9189
9190 float *help;
9191
9192 double logp[EP];
9193
9194 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
9195
9196 /* Set timer... */
9197 SELECT_TIMER("READ_MET_GEOPOT", "METPROC");
9198 LOG(2, "Calculate geopotential heights...");
9199
9200 /* Allocate... */
9201 ALLOC(help, float,
9202 EX * EY * EP);
9203
9204 /* Calculate log pressure... */
9205#pragma omp parallel for default(shared)
9206 for (int ip = 0; ip < met->np; ip++)
9207 logp[ip] = log(met->p[ip]);
9208
9209 /* Apply hydrostatic equation to calculate geopotential heights... */
9210#pragma omp parallel for default(shared) collapse(2)
9211 for (int ix = 0; ix < met->nx; ix++)
9212 for (int iy = 0; iy < met->ny; iy++) {
9213
9214 /* Get surface height and pressure... */
9215 const double zs = met->zs[ix][iy];
9216 const double lnps = log(met->ps[ix][iy]);
9217
9218 /* Get temperature and water vapor at the surface... */
9219 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
9220 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
9221 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
9222 const double h2os =
9223 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
9224 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
9225
9226 /* Upper part of profile... */
9227 met->z[ix][iy][ip0 + 1]
9228 = (float) (zs +
9229 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
9230 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
9231 for (int ip = ip0 + 2; ip < met->np; ip++)
9232 met->z[ix][iy][ip]
9233 = (float) (met->z[ix][iy][ip - 1] +
9234 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
9235 met->h2o[ix][iy][ip - 1], logp[ip],
9236 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
9237
9238 /* Lower part of profile... */
9239 met->z[ix][iy][ip0]
9240 = (float) (zs +
9241 ZDIFF(lnps, ts, h2os, logp[ip0],
9242 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
9243 for (int ip = ip0 - 1; ip >= 0; ip--)
9244 met->z[ix][iy][ip]
9245 = (float) (met->z[ix][iy][ip + 1] +
9246 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
9247 met->h2o[ix][iy][ip + 1], logp[ip],
9248 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
9249 }
9250
9251 /* Check control parameters... */
9252 if (dx == 0 || dy == 0)
9253 return;
9254
9255 /* Default smoothing parameters... */
9256 if (dx < 0 || dy < 0) {
9257 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
9258 dx = 3;
9259 dy = 2;
9260 } else {
9261 dx = 6;
9262 dy = 4;
9263 }
9264 }
9265
9266 /* Calculate weights for smoothing... */
9267 float ws[dx + 1][dy + 1];
9268#pragma omp parallel for default(shared) collapse(2)
9269 for (int ix = 0; ix <= dx; ix++)
9270 for (int iy = 0; iy < dy; iy++)
9271 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
9272 * (1.0f - (float) iy / (float) dy);
9273
9274 /* Copy data... */
9275#pragma omp parallel for default(shared) collapse(3)
9276 for (int ix = 0; ix < met->nx; ix++)
9277 for (int iy = 0; iy < met->ny; iy++)
9278 for (int ip = 0; ip < met->np; ip++)
9279 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
9280
9281 /* Horizontal smoothing... */
9282#pragma omp parallel for default(shared) collapse(3)
9283 for (int ip = 0; ip < met->np; ip++)
9284 for (int ix = 0; ix < met->nx; ix++)
9285 for (int iy = 0; iy < met->ny; iy++) {
9286 float res = 0, wsum = 0;
9287 int iy0 = MAX(iy - dy + 1, 0);
9288 int iy1 = MIN(iy + dy - 1, met->ny - 1);
9289 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
9290 int ix3 = ix2;
9291 if (ix3 < 0)
9292 ix3 += met->nx;
9293 else if (ix3 >= met->nx)
9294 ix3 -= met->nx;
9295 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
9296 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
9297 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
9298 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
9299 wsum += w;
9300 }
9301 }
9302 if (wsum > 0)
9303 met->z[ix][iy][ip] = res / wsum;
9304 else
9305 met->z[ix][iy][ip] = NAN;
9306 }
9307
9308 /* Free... */
9309 free(help);
9310}
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:2064
Here is the call graph for this function:

◆ read_met_nc_grid()

void read_met_nc_grid ( const char *  filename,
const int  ncid,
const ctl_t ctl,
met_t met,
dd_t dd 
)

Reads meteorological grid data from NetCDF files with domain decomposition.

The read_met_nc_grid function reads meteorological data from NetCDF files and processes it with domain decomposition for parallel processing. It extracts time information, grid dimensions, and coordinates, and sets up hyperslabs for subdomains and halos. It also reads pressure levels and handles model level and surface data.

Parameters
filenameA string representing the filename of the NetCDF file to read.
ncidA NetCDF file ID.
ctlA pointer to a ctl_t structure containing control parameters.
metA pointer to a met_t structure where meteorological data will be stored.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.

The function performs the following steps:

  • Sets filenames for meteorological data files.
  • Extracts time information from the filename or NetCDF file.
  • Validates the time information and logs it.
  • Retrieves global and local grid dimensions and checks for regular grid spacing.
  • Sets up hyperslabs for subdomains and halos, considering edge cases.
  • Adjusts grid dimensions and coordinates for subdomains and halos.
  • Reads pressure levels and computes the 3D pressure field.
  • Handles model level and surface data using GRIB handles.
  • Reads grid data and surface data from the respective files.
  • Computes the 3D pressure field and reads model level data.
Note
This function assumes that the input filename and structures are properly initialized. It uses MPI for parallel processing and handles domain decomposition. The function is designed to work with NetCDF and GRIB file formats. It logs various stages of processing for debugging and validation purposes.
Author
Lars Hoffmann
Jan Clemens

Definition at line 9314 of file mptrac.c.

9319 {
9320
9321 char levname[LEN], tstr[10];
9322
9323 double rtime = 0, r, r2;
9324
9325 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
9326 year, mon, day, hour, min, sec;
9327
9328 size_t dimlen;
9329
9330 /* Set timer... */
9331 SELECT_TIMER("READ_MET_NC_GRID", "INPUT");
9332 LOG(2, "Read meteo grid information...");
9333
9334 /* MPTRAC meteo files... */
9335 if (!ctl->met_clams) {
9336
9337 /* Get time from filename... */
9338 met->time = time_from_filename(filename, 16, 0);
9339
9340 /* Check time information from data file... */
9341 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
9342 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
9343 NC(nc_get_var_double(ncid, varid, &rtime));
9344 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
9345 WARN("Time information in meteo file does not match filename!");
9346 } else
9347 WARN("Time information in meteo file is missing!");
9348 }
9349
9350 /* CLaMS meteo files... */
9351 else {
9352
9353 /* Read time from file... */
9354 NC_GET_DOUBLE("time", &rtime, 0);
9355
9356 /* Get time from filename (considering the century)... */
9357 if (rtime < 0)
9358 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
9359 else
9360 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
9361 year = atoi(tstr);
9362 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
9363 mon = atoi(tstr);
9364 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
9365 day = atoi(tstr);
9366 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
9367 hour = atoi(tstr);
9368 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
9369 }
9370
9371 /* Check time... */
9372 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
9373 || day < 1 || day > 31 || hour < 0 || hour > 23)
9374 ERRMSG("Cannot read time from filename!");
9375 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
9376 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
9377 met->time, year2, mon2, day2, hour2, min2);
9378
9379 /* Get vertical dimension... */
9380 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
9381 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
9382 ERRMSG
9383 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
9384
9385 NC(nc_inq_varndims(ncid, varid, &ndims));
9386 NC(nc_inq_vardimid(ncid, varid, dimids));
9387
9388 if (ndims == 4) {
9389 NC(nc_inq_dim
9390 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
9391 } else if (ndims == 3) {
9392 NC(nc_inq_dim
9393 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
9394 } else
9395 ERRMSG("Cannot determine vertical dimension!")
9396 met->np = (int) dimlen;
9397
9398 LOG(2, "Number of levels: %d", met->np);
9399 if (met->np < 2 || met->np > EP)
9400 ERRMSG("Number of levels out of range!");
9401
9402 if (!ctl->dd) {
9403
9404 /* Get grid dimensions and coordinates... */
9405 if (met->coord_type == 0) {
9406 /* Longitude/latitude grid... */
9407 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
9408 LOG(2, "Number of longitudes: %d", met->nx);
9409
9410 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
9411 LOG(2, "Number of latitudes: %d", met->ny);
9412
9413 NC_GET_DOUBLE("lon", met->lon, 1);
9414 LOG(2, "Longitudes: %g, %g ... %g deg",
9415 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9416 NC_GET_DOUBLE("lat", met->lat, 1);
9417 LOG(2, "Latitudes: %g, %g ... %g deg",
9418 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9419
9420 } else {
9421 /* UTM grid... */
9422 NC_INQ_DIM("x", &met->nx, 2, EX, 1);
9423 LOG(2, "Number of x coordinates: %d", met->nx);
9424
9425 NC_INQ_DIM("y", &met->ny, 2, EY, 1);
9426 LOG(2, "Number of y coordinates: %d", met->ny);
9427
9428 NC_GET_DOUBLE("x", met->lon, 1);
9429 LOG(2, "X coordinates: %g, %g ... %g m",
9430 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9431 NC_GET_DOUBLE("y", met->lat, 1);
9432 LOG(2, "Y coordinates: %g, %g ... %g m",
9433 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9434 }
9435
9436 } else {
9437
9438 if (met->coord_type != 0)
9439 ERRMSG("Domain decomposition is only supported for lat/lon grids!");
9440
9441 /* Use equidistant lat-lon domain decomposition... */
9442 dd_read_met_nc_grid(dd, ctl, met, ncid);
9443
9444 }
9445
9446 /* Read pressure levels... */
9447 if (ctl->met_np <= 0) {
9448 NC_GET_DOUBLE(levname, met->p, 1);
9449 for (int ip = 0; ip < met->np; ip++)
9450 met->p[ip] /= 100.;
9451 LOG(2, "Altitude levels: %g, %g ... %g km",
9452 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
9453 LOG(2, "Pressure levels: %g, %g ... %g hPa",
9454 met->p[0], met->p[1], met->p[met->np - 1]);
9455 }
9456
9457 /* Read hybrid levels... */
9458 if (strcasecmp(levname, "hybrid") == 0)
9459 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
9460
9461 /* Read model level coefficients from file... */
9462 if (ctl->met_vert_coord == 2) {
9463 NC_GET_DOUBLE("hyam", met->hyam, 1);
9464 NC_GET_DOUBLE("hybm", met->hybm, 1);
9465 }
9466
9467 /* Copy model level coefficients from control parameters... */
9468 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
9469 if (ctl->met_nlev <= 0)
9470 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
9471 for (int ip = 0; ip < ctl->met_nlev; ip++) {
9472 met->hyam[ip] = ctl->met_lev_hyam[ip];
9473 met->hybm[ip] = ctl->met_lev_hybm[ip];
9474 }
9475 }
9476
9477 /* Calculate eta levels... */
9478 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
9479 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
9480 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
9481 ERRMSG("Eta levels must be ascending!");
9482 }
9483
9484 /* Check horizontal grid spacing... */
9485 for (int ix = 2; ix < met->nx; ix++)
9486 if (fabs
9487 (fabs(met->lon[ix] - met->lon[ix - 1]) -
9488 fabs(met->lon[1] - met->lon[0])) > 0.001)
9489 ERRMSG("No regular grid spacing in longitudes!");
9490 for (int iy = 2; iy < met->ny; iy++)
9491 if (fabs
9492 (fabs(met->lat[iy] - met->lat[iy - 1]) -
9493 fabs(met->lat[1] - met->lat[0])) > 0.001) {
9494 WARN("No regular grid spacing in latitudes!");
9495 break;
9496 }
9497}
void dd_read_met_nc_grid(dd_t *dd, const ctl_t *ctl, met_t *met, const int ncid)
Read meteorological grid information and construct the domain-decomposed grid with halo regions.
Definition: mptrac.c:11077
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:12283
double time_from_filename(const char *filename, const int offset, const int with_seconds)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:12382
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3625
double eta[EP]
Model level eta values.
Definition: mptrac.h:3634
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3628
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3631
Here is the call graph for this function:

◆ read_met_nc_surface()

void read_met_nc_surface ( const int  ncid,
const ctl_t ctl,
met_t met,
dd_t dd 
)

Reads and processes surface meteorological data from NetCDF files with domain decomposition.

The read_met_nc_surface function reads surface meteorological data from a NetCDF file and processes it for use in a domain decomposition context. It handles various surface parameters such as pressure, geopotential height, temperature, wind components, and other relevant meteorological data. The function is designed to work with different meteorological data formats and configurations.

Parameters
ncidAn integer representing the NetCDF file ID.
ctlA pointer to a ctl_t structure containing control parameters and settings.
metA pointer to a met_t structure where surface meteorological data will be stored.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.

The function performs the following steps:

  • Reads surface pressure data and converts it if necessary.
  • Handles different data formats for MPTRAC and CLaMS meteorological data.
  • Reads geopotential height at the surface and processes it based on the data format.
  • Optionally converts zm surface geopotential data from m^2 s^-2 to km when MET_GP2Z = 1.
  • Retrieves surface temperature, zonal and meridional wind, and other surface parameters.
  • Logs warnings if specific data fields cannot be read.
  • Uses helper functions to read 2D and 3D data fields from the NetCDF file.
  • Processes and stores the read data into the provided meteorological data structure.
Note
This function assumes that the NetCDF file ID and structures are properly initialized. It is designed to work with NetCDF files and uses MPI for parallel processing. The function logs warnings for missing or unreadable data fields and handles different data formats.
Author
Lars Hoffmann
Jan Clemens

Definition at line 9501 of file mptrac.c.

9505 {
9506
9507 /* Set timer... */
9508 SELECT_TIMER("READ_MET_SURFACE", "INPUT");
9509 LOG(2, "Read surface data...");
9510
9511 /* Read surface pressure... */
9512 if (read_met_nc_2d
9513 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
9514 1.0f, 1)) {
9515 for (int ix = 0; ix < met->nx; ix++)
9516 for (int iy = 0; iy < met->ny; iy++)
9517 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
9518 } else
9519 if (!read_met_nc_2d
9520 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
9521 0.01f, 1)) {
9522 WARN("Cannot not read surface pressure data (use lowest level)!");
9523 for (int ix = 0; ix < met->nx; ix++)
9524 for (int iy = 0; iy < met->ny; iy++)
9525 met->ps[ix][iy]
9526 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
9527 }
9528
9529 /* MPTRAC meteo data... */
9530 if (ctl->met_clams == 0) {
9531
9532 /* Read geopotential height at the surface... */
9533 if (!read_met_nc_2d
9534 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
9535 (float) (1. / (1000. * G0)), 1))
9536 if (!read_met_nc_2d
9537 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
9538 (ctl->met_gp2z ? (float) (1e-3 / G0) : (float) (1. / 1000.)), 1))
9539 WARN("Cannot read surface geopotential height!");
9540 }
9541
9542 /* CLaMS meteo data... */
9543 else {
9544
9545 /* Read geopotential height at the surface
9546 (use lowermost level of 3-D data field)... */
9547 float *help;
9548 ALLOC(help, float,
9549 EX * EY * EP);
9550 memcpy(help, met->pl, sizeof(met->pl));
9551 if (!read_met_nc_3d
9552 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
9553 (float) (1e-3 / G0)))
9554 ERRMSG("Cannot read geopotential height!");
9555 for (int ix = 0; ix < met->nx; ix++)
9556 for (int iy = 0; iy < met->ny; iy++)
9557 met->zs[ix][iy] = met->pl[ix][iy][0];
9558 memcpy(met->pl, help, sizeof(met->pl));
9559 free(help);
9560 }
9561
9562 /* Read temperature at the surface... */
9563 if (!read_met_nc_2d
9564 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
9565 1))
9566 WARN("Cannot read surface temperature!");
9567
9568 /* Read zonal wind at the surface... */
9569 if (!read_met_nc_2d
9570 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
9571 met->us, 1.0, 1))
9572 WARN("Cannot read surface zonal wind!");
9573
9574 /* Read meridional wind at the surface... */
9575 if (!read_met_nc_2d
9576 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
9577 met->vs, 1.0, 1))
9578 WARN("Cannot read surface meridional wind!");
9579
9580 /* Read eastward turbulent surface stress... */
9581 if (!read_met_nc_2d
9582 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
9583 1.0, 1))
9584 WARN("Cannot read eastward turbulent surface stress!");
9585
9586 /* Read northward turbulent surface stress... */
9587 if (!read_met_nc_2d
9588 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
9589 1.0, 1))
9590 WARN("Cannot read nothward turbulent surface stress!");
9591
9592 /* Read surface sensible heat flux... */
9593 if (!read_met_nc_2d
9594 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
9595 1.0, 1))
9596 WARN("Cannot read surface sensible heat flux!");
9597
9598 /* Read land-sea mask... */
9599 if (!read_met_nc_2d
9600 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
9601 1.0, 1))
9602 WARN("Cannot read land-sea mask!");
9603
9604 /* Read sea surface temperature... */
9605 if (!read_met_nc_2d
9606 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
9607 1.0, 1))
9608 WARN("Cannot read sea surface temperature!");
9609
9610 /* Read PBL... */
9611 if (ctl->met_pbl == 0)
9612 if (!read_met_nc_2d
9613 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
9614 0.01f, 1))
9615 WARN("Cannot read planetary boundary layer pressure!");
9616 if (ctl->met_pbl == 1)
9617 if (!read_met_nc_2d
9618 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
9619 0.001f, 1))
9620 WARN("Cannot read planetary boundary layer height!");
9621
9622 /* Read CAPE... */
9623 if (ctl->met_cape == 0)
9624 if (!read_met_nc_2d
9625 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
9626 met->cape, 1.0, 1))
9627 WARN("Cannot read CAPE!");
9628
9629 /* Read CIN... */
9630 if (ctl->met_cape == 0)
9631 if (!read_met_nc_2d
9632 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
9633 1.0, 1))
9634 WARN("Cannot read convective inhibition!");
9635}
int read_met_nc_2d(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const char *varname5, const char *varname6, const ctl_t *ctl, const met_t *met, dd_t *dd, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:9836
int read_met_nc_3d(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const ctl_t *ctl, const met_t *met, dd_t *dd, float dest[EX][EY][EP], const float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:10158
Here is the call graph for this function:

◆ read_met_nc_levels()

void read_met_nc_levels ( const int  ncid,
const ctl_t ctl,
met_t met,
dd_t dd 
)

Reads and processes meteorological level data from NetCDF files with domain decomposition.

The read_met_nc_levels function reads meteorological level data from a NetCDF file and processes it for use in a domain decomposition context. It handles various meteorological parameters such as temperature, wind components, humidity, ozone, cloud data, and vertical velocity. The function also processes pressure levels and interpolates data between model and pressure levels as needed.

Parameters
ncidAn integer representing the NetCDF file ID.
ctlA pointer to a ctl_t structure containing control parameters and settings.
metA pointer to a met_t structure where meteorological level data will be stored.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.

The function performs the following steps:

  • Reads temperature, horizontal wind components, and vertical velocity data.
  • Processes water vapor data, handling both specific and relative humidity.
  • Reads ozone and various cloud-related data such as liquid water content, ice water content, and cloud cover.
  • Processes zeta and zeta_dot data.
  • Stores velocities on model levels and saves the number of model levels.
  • Computes pressure on model levels using different methods based on control parameters.
  • Checks the ordering of pressure levels to ensure they are monotonic.
  • Interpolates meteorological variables from model levels to pressure levels if specified.
  • Validates the ordering of pressure levels to ensure they are in descending order.
Note
This function assumes that the NetCDF file ID and structures are properly initialized. It is designed to work with NetCDF files and uses OpenMP for parallel processing. The function logs errors and warnings for missing or unreadable data fields and handles different data formats.
Author
Lars Hoffmann
Jan Clemens

Definition at line 9639 of file mptrac.c.

9643 {
9644
9645 /* Set timer... */
9646 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT");
9647 LOG(2, "Read level data...");
9648
9649 /* Read temperature... */
9650 if (!read_met_nc_3d
9651 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
9652 ERRMSG("Cannot read temperature!");
9653
9654 /* Read horizontal wind and vertical velocity... */
9655 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
9656 ERRMSG("Cannot read zonal wind!");
9657 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
9658 ERRMSG("Cannot read meridional wind!");
9659 if (!read_met_nc_3d
9660 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
9661 WARN("Cannot read vertical velocity!");
9662
9663 /* Read water vapor... */
9664 if (!ctl->met_relhum) {
9665 if (!read_met_nc_3d
9666 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
9667 (float) (MA / MH2O)))
9668 WARN("Cannot read specific humidity!");
9669 } else {
9670 if (!read_met_nc_3d
9671 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
9672 WARN("Cannot read relative humidity!");
9673#pragma omp parallel for default(shared) collapse(2)
9674 for (int ix = 0; ix < met->nx; ix++)
9675 for (int iy = 0; iy < met->ny; iy++)
9676 for (int ip = 0; ip < met->np; ip++) {
9677 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
9678 met->h2o[ix][iy][ip] =
9679 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
9680 }
9681 }
9682
9683 /* Read ozone... */
9684 if (!read_met_nc_3d
9685 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
9686 (float) (MA / MO3)))
9687 WARN("Cannot read ozone data!");
9688
9689 /* Read cloud data... */
9690 if (!read_met_nc_3d
9691 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
9692 WARN("Cannot read cloud liquid water content!");
9693 if (!read_met_nc_3d
9694 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
9695 WARN("Cannot read cloud rain water content!");
9696 if (!read_met_nc_3d
9697 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
9698 WARN("Cannot read cloud ice water content!");
9699 if (!read_met_nc_3d
9700 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
9701 WARN("Cannot read cloud snow water content!");
9702 if (!read_met_nc_3d
9703 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
9704 WARN("Cannot read cloud cover!");
9705
9706 /* Read zeta and zeta_dot... */
9707 if (ctl->advect_vert_coord == 1) {
9708 if (!read_met_nc_3d
9709 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
9710 WARN("Cannot read ZETA!");
9711 if (!read_met_nc_3d
9712 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
9713 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
9714 WARN("Cannot read ZETA_DOT!");
9715 }
9716
9717 /* Read eta and eta_dot... */
9718 else if (ctl->advect_vert_coord == 3) {
9719#pragma omp parallel for default(shared)
9720 for (int ix = 0; ix < met->nx; ix++)
9721 for (int iy = 0; iy < met->ny; iy++)
9722 for (int ip = 0; ip < met->np; ip++)
9723 met->zetal[ix][iy][ip] =
9724 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
9725 if (!read_met_nc_3d
9726 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
9727 1.0))
9728 WARN("Cannot read eta vertical velocity!");
9729 }
9730
9731 /* Store velocities on model levels... */
9732 if (ctl->met_vert_coord != 0) {
9733#pragma omp parallel for default(shared)
9734 for (int ix = 0; ix < met->nx; ix++)
9735 for (int iy = 0; iy < met->ny; iy++)
9736 for (int ip = 0; ip < met->np; ip++) {
9737 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
9738 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
9739 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
9740 }
9741
9742 /* Save number of model levels... */
9743 met->npl = met->np;
9744 }
9745
9746 /* Get pressure on model levels... */
9747 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
9748
9749 /* Read 3-D pressure field... */
9750 if (ctl->met_vert_coord == 1) {
9751 if (!read_met_nc_3d
9752 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
9753 0.01f))
9754 if (!read_met_nc_3d
9755 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
9756 ERRMSG("Cannot read pressure on model levels!");
9757 }
9758
9759 /* Use a and b coefficients for full levels (at layer midpoints)... */
9760 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
9761
9762 /* Check number of levels... */
9763 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
9764 ERRMSG("Mismatch in number of model levels!");
9765
9766 /* Calculate pressure... */
9767 for (int ix = 0; ix < met->nx; ix++)
9768 for (int iy = 0; iy < met->ny; iy++)
9769 for (int ip = 0; ip < met->np; ip++)
9770 met->pl[ix][iy][ip] =
9771 (float) (met->hyam[ip] / 100. +
9772 met->hybm[ip] * met->ps[ix][iy]);
9773 }
9774
9775 /* Use a and b coefficients for half levels (at layer interfaces)... */
9776 else if (ctl->met_vert_coord == 4) {
9777
9778 /* Check number of levels... */
9779 if (met->np + 1 != ctl->met_nlev)
9780 ERRMSG("Mismatch in number of model levels!");
9781
9782 /* Calculate pressure... */
9783#pragma omp parallel for default(shared) collapse(2)
9784 for (int ix = 0; ix < met->nx; ix++)
9785 for (int iy = 0; iy < met->ny; iy++)
9786 for (int ip = 0; ip < met->np; ip++) {
9787 const double p0 =
9788 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
9789 const double p1 =
9790 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
9791 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
9792 }
9793 }
9794
9795 /* Check ordering of pressure levels... */
9796 for (int ix = 0; ix < met->nx; ix++)
9797 for (int iy = 0; iy < met->ny; iy++)
9798 for (int ip = 1; ip < met->np; ip++)
9799 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
9800 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
9801 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
9802 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
9803 ERRMSG("Pressure profiles are not monotonic!");
9804 }
9805
9806 /* Interpolate from model levels to pressure levels... */
9807 if (ctl->met_np > 0) {
9808
9809 /* Interpolate variables... */
9810 read_met_ml2pl(ctl, met, met->t, "T");
9811 read_met_ml2pl(ctl, met, met->u, "U");
9812 read_met_ml2pl(ctl, met, met->v, "V");
9813 read_met_ml2pl(ctl, met, met->w, "W");
9814 read_met_ml2pl(ctl, met, met->h2o, "H2O");
9815 read_met_ml2pl(ctl, met, met->o3, "O3");
9816 read_met_ml2pl(ctl, met, met->lwc, "LWC");
9817 read_met_ml2pl(ctl, met, met->rwc, "RWC");
9818 read_met_ml2pl(ctl, met, met->iwc, "IWC");
9819 read_met_ml2pl(ctl, met, met->swc, "SWC");
9820 read_met_ml2pl(ctl, met, met->cc, "CC");
9821
9822 /* Set new pressure levels... */
9823 met->np = ctl->met_np;
9824 for (int ip = 0; ip < met->np; ip++)
9825 met->p[ip] = ctl->met_p[ip];
9826 }
9827
9828 /* Check ordering of pressure levels... */
9829 for (int ip = 1; ip < met->np; ip++)
9830 if (met->p[ip - 1] < met->p[ip])
9831 ERRMSG("Pressure levels must be descending!");
9832}
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:10907
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:295
#define MO3
Molar mass of ozone [g/mol].
Definition: mptrac.h:300
Here is the call graph for this function:

◆ read_met_nc_2d()

int read_met_nc_2d ( const int  ncid,
const char *  varname,
const char *  varname2,
const char *  varname3,
const char *  varname4,
const char *  varname5,
const char *  varname6,
const ctl_t ctl,
const met_t met,
dd_t dd,
float  dest[EX][EY],
const float  scl,
const int  init 
)

Reads a 2-dimensional meteorological variable from a NetCDF file.

This function reads a 2-dimensional meteorological variable from a NetCDF file and stores it in a specified destination array. It supports both packed and unpacked data formats and handles missing values and scaling factors accordingly. The function also checks the meteorological data layout to ensure correct data copying.

Parameters
ncidThe NetCDF file ID.
varnameThe name of the variable to read.
varname2An alternative name of the variable to read (in case varname is not found).
varname3An alternative name of the variable to read (in case varname2 is not found).
varname4An alternative name of the variable to read (in case varname3 is not found).
varname5An alternative name of the variable to read (in case varname4 is not found).
varname6An alternative name of the variable to read (in case varname5 is not found).
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.
destThe destination array to store the read data.
sclA scaling factor to apply to the read data.
initFlag indicating whether to initialize the destination array before reading.
Returns
Returns 1 on success, 0 on failure.

The function performs the following steps:

  • Checks if the specified variable exists in the NetCDF file.
  • Reads packed data if scaling factors are available, otherwise reads unpacked data.
  • Handles missing values and scaling factors appropriately.
  • Copies the data to the destination array, applying the scaling factor if provided.
Author
Lars Hoffmann

Definition at line 9836 of file mptrac.c.

9849 {
9850
9851 char varsel[LEN];
9852
9853 float offset, scalfac;
9854
9855 int varid;
9856
9857 /* Check if variable exists... */
9858 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9859 sprintf(varsel, "%s", varname);
9860 else if (varname2 != NULL
9861 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9862 sprintf(varsel, "%s", varname2);
9863 else if (varname3 != NULL
9864 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9865 sprintf(varsel, "%s", varname3);
9866 else if (varname4 != NULL
9867 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9868 sprintf(varsel, "%s", varname4);
9869 else if (varname5 != NULL
9870 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
9871 sprintf(varsel, "%s", varname5);
9872 else if (varname6 != NULL
9873 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
9874 sprintf(varsel, "%s", varname6);
9875 else
9876 return 0;
9877
9878 /* Read packed data... */
9879 if (ctl->met_nc_scale && !ctl->dd
9880 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9881 && nc_get_att_float(ncid, varid, "scale_factor",
9882 &scalfac) == NC_NOERR) {
9883
9884 /* Allocate... */
9885 short *help;
9886 ALLOC(help, short,
9887 EX * EY * EP);
9888
9889 /* Read fill value and missing value... */
9890 short fillval, missval;
9891 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9892 fillval = 0;
9893 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9894 missval = 0;
9895
9896 /* Write info... */
9897 LOG(2, "Read 2-D variable: %s"
9898 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9899 varsel, fillval, missval, scalfac, offset);
9900
9901 /* Read data... */
9902 NC(nc_get_var_short(ncid, varid, help));
9903
9904 /* Check meteo data layout... */
9905 if (ctl->met_convention != 0)
9906 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9907
9908 /* Copy and check data... */
9909 omp_set_dynamic(1);
9910#pragma omp parallel for default(shared)
9911 for (int ix = 0; ix < met->nx; ix++)
9912 for (int iy = 0; iy < met->ny; iy++) {
9913 if (init)
9914 dest[ix][iy] = 0;
9915 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
9916 if ((fillval == 0 || aux != fillval)
9917 && (missval == 0 || aux != missval)
9918 && fabsf(aux * scalfac + offset) < 1e14f)
9919 dest[ix][iy] += scl * (aux * scalfac + offset);
9920 else
9921 dest[ix][iy] = NAN;
9922 }
9923 omp_set_dynamic(0);
9924
9925 /* Free... */
9926 free(help);
9927 }
9928
9929 /* Unpacked data... */
9930 else if (!ctl->dd) {
9931
9932 /* Allocate... */
9933 float *help;
9934 ALLOC(help, float,
9935 EX * EY);
9936
9937 /* Read fill value and missing value... */
9938 float fillval, missval;
9939 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9940 fillval = 0;
9941 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9942 missval = 0;
9943
9944 /* Write info... */
9945 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
9946 varsel, fillval, missval);
9947
9948 /* Read data... */
9949 NC(nc_get_var_float(ncid, varid, help));
9950
9951 /* Check meteo data layout... */
9952 if (ctl->met_convention == 0) {
9953
9954 /* Copy and check data (ordering: lat, lon)... */
9955 omp_set_dynamic(1);
9956#pragma omp parallel for default(shared)
9957 for (int ix = 0; ix < met->nx; ix++)
9958 for (int iy = 0; iy < met->ny; iy++) {
9959 if (init)
9960 dest[ix][iy] = 0;
9961 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
9962 if ((fillval == 0 || aux != fillval)
9963 && (missval == 0 || aux != missval)
9964 && fabsf(aux) < 1e14f)
9965 dest[ix][iy] += scl * aux;
9966 else
9967 dest[ix][iy] = NAN;
9968 }
9969 omp_set_dynamic(0);
9970
9971 } else {
9972
9973 /* Copy and check data (ordering: lon, lat)... */
9974 omp_set_dynamic(1);
9975#pragma omp parallel for default(shared)
9976 for (int iy = 0; iy < met->ny; iy++)
9977 for (int ix = 0; ix < met->nx; ix++) {
9978 if (init)
9979 dest[ix][iy] = 0;
9980 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
9981 if ((fillval == 0 || aux != fillval)
9982 && (missval == 0 || aux != missval)
9983 && fabsf(aux) < 1e14f)
9984 dest[ix][iy] += scl * aux;
9985 else
9986 dest[ix][iy] = NAN;
9987 }
9988 omp_set_dynamic(0);
9989 }
9990
9991 /* Free... */
9992 free(help);
9993 }
9994
9995 /* Domain decomposed data... */
9996 else {
9997
9998 /* Read fill value and missing value... */
9999 float fillval, missval;
10000 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10001 fillval = 0;
10002 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10003 missval = 0;
10004
10005 /* Write info... */
10006 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
10007 varsel, fillval, missval);
10008
10009 /* Define hyperslab... */
10010 float *help;
10011 size_t help_subdomain_start[3];
10012 size_t help_subdomain_count[3];
10013
10014 help_subdomain_start[0] = 0;
10015 if (ctl->met_convention == 0) {
10016 help_subdomain_start[1] = dd->subdomain_start[2];
10017 help_subdomain_start[2] = dd->subdomain_start[3];
10018 } else {
10019 help_subdomain_start[1] = dd->subdomain_start[3];
10020 help_subdomain_start[2] = dd->subdomain_start[2];
10021 }
10022
10023 help_subdomain_count[0] = 1;
10024 if (ctl->met_convention == 0) {
10025 help_subdomain_count[1] = dd->subdomain_count[2]; //y
10026 help_subdomain_count[2] = dd->subdomain_count[3]; //x
10027 } else {
10028 help_subdomain_count[1] = dd->subdomain_count[3]; //x
10029 help_subdomain_count[2] = dd->subdomain_count[2]; //y
10030 }
10031
10032 ALLOC(help, float,
10033 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
10034
10035 /* Read data... */
10036#ifdef DD
10037 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
10038#endif
10039 NC(nc_get_vara_float
10040 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
10041
10042 /* Read halos at boundaries... */
10043 size_t help_halo_bnd_start[3];
10044 size_t help_halo_bnd_count[3];
10045
10046 help_halo_bnd_start[0] = 0;
10047 if (ctl->met_convention == 0) {
10048 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
10049 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
10050 } else {
10051 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
10052 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
10053 }
10054
10055 help_halo_bnd_count[0] = 1;
10056 if (ctl->met_convention == 0) {
10057 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
10058 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
10059 } else {
10060 help_halo_bnd_count[1] = dd->halo_bnd_count[3]; //x
10061 help_halo_bnd_count[2] = dd->halo_bnd_count[2]; //y
10062 }
10063
10064 float *help_halo;
10065 ALLOC(help_halo, float,
10066 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
10067
10068#ifdef DD
10069 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
10070#endif
10071 NC(nc_get_vara_float
10072 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
10073
10074 /* Check meteo data layout... */
10075 if (ctl->met_convention == 0) {
10076
10077 /* Copy and check data (ordering: lat, lon)... */
10078 omp_set_dynamic(1);
10079#pragma omp parallel for default(shared)
10080 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
10081 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
10082 if (init == 1)
10083 dest[ix + dd->halo_offset_start][iy] = 0;
10084 const float aux =
10085 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
10086 if ((fillval == 0 || aux != fillval)
10087 && (missval == 0 || aux != missval)
10088 && fabsf(aux) < 1e14f) {
10089 dest[ix + dd->halo_offset_start][iy] += scl * aux;
10090 } else
10091 dest[ix + dd->halo_offset_start][iy] = NAN;
10092 }
10093
10094#pragma omp parallel for default(shared)
10095 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
10096 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
10097 if (init == 1)
10098 dest[ix + dd->halo_offset_end][iy] = 0;
10099 const float aux =
10100 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
10101 if ((fillval == 0 || aux != fillval)
10102 && (missval == 0 || aux != missval)
10103 && fabsf(aux) < 1e14f)
10104 dest[ix + dd->halo_offset_end][iy] += scl * aux;
10105 else {
10106 dest[ix + dd->halo_offset_end][iy] = NAN;
10107 }
10108 }
10109 omp_set_dynamic(0);
10110
10111 } else {
10112
10113 /* Copy and check data (ordering: lon, lat)... */
10114 omp_set_dynamic(1);
10115#pragma omp parallel for default(shared)
10116 for (int ix = 0; ix < (int) help_subdomain_count[1]; ix++)
10117 for (int iy = 0; iy < (int) help_subdomain_count[2]; iy++) {
10118 if (init == 1)
10119 dest[ix + dd->halo_offset_start][iy] = 0;
10120 const float aux =
10121 help[ARRAY_2D(ix, iy, (int) help_subdomain_count[1])];
10122 if ((fillval == 0 || aux != fillval)
10123 && (missval == 0 || aux != missval)
10124 && fabsf(aux) < 1e14f)
10125 dest[ix + dd->halo_offset_start][iy] += scl * aux;
10126 else
10127 dest[ix + dd->halo_offset_start][iy] = NAN;
10128 }
10129
10130#pragma omp parallel for default(shared)
10131 for (int ix = 0; ix < (int) help_halo_bnd_count[1]; ix++)
10132 for (int iy = 0; iy < (int) help_halo_bnd_count[2]; iy++) {
10133 if (init == 1)
10134 dest[ix + dd->halo_offset_end][iy] = 0;
10135 const float aux =
10136 help_halo[ARRAY_2D(ix, iy, (int) help_halo_bnd_count[1])];
10137 if ((fillval == 0 || aux != fillval)
10138 && (missval == 0 || aux != missval)
10139 && fabsf(aux) < 1e14f)
10140 dest[ix + dd->halo_offset_end][iy] += scl * aux;
10141 else
10142 dest[ix + dd->halo_offset_end][iy] = NAN;
10143 }
10144 omp_set_dynamic(0);
10145 }
10146
10147 /* Free... */
10148 free(help);
10149 free(help_halo);
10150 }
10151
10152 /* Return... */
10153 return 1;
10154}
size_t halo_bnd_count[4]
Extent of the periodic boundary halo hyperslab.
Definition: mptrac.h:3804
int halo_offset_end
Offset of the periodic halo block at the end of the local x-array.
Definition: mptrac.h:3810
size_t halo_bnd_start[4]
Start indices of the periodic boundary halo hyperslab.
Definition: mptrac.h:3801
int halo_offset_start
Offset of the periodic halo block at the beginning of the local x-array.
Definition: mptrac.h:3807
size_t subdomain_count[4]
Extent of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:3798
size_t subdomain_start[4]
Start indices of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:3795

◆ read_met_nc_3d()

int read_met_nc_3d ( const int  ncid,
const char *  varname,
const char *  varname2,
const char *  varname3,
const char *  varname4,
const ctl_t ctl,
const met_t met,
dd_t dd,
float  dest[EX][EY][EP],
const float  scl 
)

Reads a 3-dimensional meteorological variable from a NetCDF file.

This function reads a 3-dimensional meteorological variable from a NetCDF file and stores it in a specified destination array. It supports both packed and unpacked data formats and handles missing values and scaling factors accordingly. The function also checks the meteorological data layout to ensure correct data copying.

Parameters
ncidThe NetCDF file ID.
varnameThe name of the variable to read.
varname2An alternative name of the variable to read (in case varname is not found).
varname3An alternative name of the variable to read (in case varname2 is not found).
varname4An alternative name of the variable to read (in case varname3 is not found).
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.
destThe destination array to store the read data.
sclA scaling factor to apply to the read data.
Returns
Returns 1 on success, 0 on failure.

The function performs the following steps:

  • Checks if the specified variable exists in the NetCDF file.
  • Reads packed data if scaling factors are available, otherwise reads unpacked data.
  • Handles missing values and scaling factors appropriately.
  • Copies the data to the destination array, applying the scaling factor if provided.
Author
Lars Hoffmann

Definition at line 10158 of file mptrac.c.

10168 {
10169
10170 char varsel[LEN];
10171
10172 float offset, scalfac;
10173
10174 int varid;
10175
10176 /* Check if variable exists... */
10177 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
10178 sprintf(varsel, "%s", varname);
10179 else if (varname2 != NULL
10180 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
10181 sprintf(varsel, "%s", varname2);
10182 else if (varname3 != NULL
10183 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
10184 sprintf(varsel, "%s", varname3);
10185 else if (varname4 != NULL
10186 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
10187 sprintf(varsel, "%s", varname4);
10188 else
10189 return 0;
10190
10191 /* Read packed data... */
10192 if (ctl->met_nc_scale && !ctl->dd
10193 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
10194 && nc_get_att_float(ncid, varid, "scale_factor",
10195 &scalfac) == NC_NOERR) {
10196
10197 /* Allocate... */
10198 short *help;
10199 ALLOC(help, short,
10200 EX * EY * EP);
10201
10202 /* Read fill value and missing value... */
10203 short fillval, missval;
10204 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10205 fillval = 0;
10206 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
10207 missval = 0;
10208
10209 /* Write info... */
10210 LOG(2, "Read 3-D variable: %s "
10211 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
10212 varsel, fillval, missval, scalfac, offset);
10213
10214 /* Read data... */
10215 NC(nc_get_var_short(ncid, varid, help));
10216
10217 /* Check meteo data layout... */
10218 if (ctl->met_convention != 0)
10219 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
10220
10221 /* Copy and check data... */
10222 omp_set_dynamic(1);
10223#pragma omp parallel for default(shared)
10224 for (int ix = 0; ix < met->nx; ix++)
10225 for (int iy = 0; iy < met->ny; iy++)
10226 for (int ip = 0; ip < met->np; ip++) {
10227 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
10228 if ((fillval == 0 || aux != fillval)
10229 && (missval == 0 || aux != missval)
10230 && fabsf(aux * scalfac + offset) < 1e14f)
10231 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
10232 else
10233 dest[ix][iy][ip] = NAN;
10234 }
10235 omp_set_dynamic(0);
10236
10237 /* Free... */
10238 free(help);
10239 }
10240
10241 /* Unpacked data... */
10242 else if (!ctl->dd) {
10243
10244 /* Allocate... */
10245 float *help;
10246 ALLOC(help, float,
10247 EX * EY * EP);
10248
10249 /* Read fill value and missing value... */
10250 float fillval, missval;
10251 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10252 fillval = 0;
10253 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10254 missval = 0;
10255
10256 /* Write info... */
10257 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
10258 varsel, fillval, missval);
10259
10260 /* Read data... */
10261 NC(nc_get_var_float(ncid, varid, help));
10262
10263 /* Check meteo data layout... */
10264 if (ctl->met_convention == 0) {
10265
10266 /* Copy and check data (ordering: lev, lat, lon)... */
10267 omp_set_dynamic(1);
10268#pragma omp parallel for default(shared)
10269 for (int ix = 0; ix < met->nx; ix++)
10270 for (int iy = 0; iy < met->ny; iy++)
10271 for (int ip = 0; ip < met->np; ip++) {
10272 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
10273 if ((fillval == 0 || aux != fillval)
10274 && (missval == 0 || aux != missval)
10275 && fabsf(aux) < 1e14f)
10276 dest[ix][iy][ip] = scl * aux;
10277 else
10278 dest[ix][iy][ip] = NAN;
10279 }
10280 omp_set_dynamic(0);
10281
10282 } else {
10283
10284 /* Copy and check data (ordering: lon, lat, lev)... */
10285 omp_set_dynamic(1);
10286#pragma omp parallel for default(shared)
10287 for (int ip = 0; ip < met->np; ip++)
10288 for (int iy = 0; iy < met->ny; iy++)
10289 for (int ix = 0; ix < met->nx; ix++) {
10290 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
10291 if ((fillval == 0 || aux != fillval)
10292 && (missval == 0 || aux != missval)
10293 && fabsf(aux) < 1e14f)
10294 dest[ix][iy][ip] = scl * aux;
10295 else
10296 dest[ix][iy][ip] = NAN;
10297 }
10298 omp_set_dynamic(0);
10299 }
10300
10301 /* Free... */
10302 free(help);
10303 }
10304
10305 /* Domain decomposed data... */
10306 else {
10307
10308 /* Read fill value and missing value... */
10309 float fillval, missval;
10310 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10311 fillval = 0;
10312 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10313 missval = 0;
10314
10315 /* Write info... */
10316 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
10317 varsel, fillval, missval);
10318
10319 /* Define hyperslab... */
10320 size_t help_subdomain_start[4];
10321 size_t help_subdomain_count[4];
10322 size_t help_halo_bnd_start[4];
10323 size_t help_halo_bnd_count[4];
10324
10325 if (ctl->met_convention == 0) {
10326 for (int i = 0; i < 4; i++) {
10327 help_subdomain_start[i] = dd->subdomain_start[i];
10328 help_subdomain_count[i] = dd->subdomain_count[i];
10329 help_halo_bnd_start[i] = dd->halo_bnd_start[i];
10330 help_halo_bnd_count[i] = dd->halo_bnd_count[i];
10331 }
10332 } else {
10333 help_subdomain_start[0] = dd->subdomain_start[0];
10334 help_subdomain_start[1] = dd->subdomain_start[3];
10335 help_subdomain_start[2] = dd->subdomain_start[2];
10336 help_subdomain_start[3] = dd->subdomain_start[1];
10337
10338 help_subdomain_count[0] = dd->subdomain_count[0];
10339 help_subdomain_count[1] = dd->subdomain_count[3];
10340 help_subdomain_count[2] = dd->subdomain_count[2];
10341 help_subdomain_count[3] = dd->subdomain_count[1];
10342
10343 help_halo_bnd_start[0] = dd->halo_bnd_start[0];
10344 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
10345 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
10346 help_halo_bnd_start[3] = dd->halo_bnd_start[1];
10347
10348 help_halo_bnd_count[0] = dd->halo_bnd_count[0];
10349 help_halo_bnd_count[1] = dd->halo_bnd_count[3];
10350 help_halo_bnd_count[2] = dd->halo_bnd_count[2];
10351 help_halo_bnd_count[3] = dd->halo_bnd_count[1];
10352 }
10353
10354 /* Allocate... */
10355 float *help;
10356 ALLOC(help, float,
10357 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
10358 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
10359
10360 /* Use default NetCDF parallel I/O behavior */
10361#ifdef DD
10362 NC(nc_var_par_access(ncid, varid, NC_INDEPENDENT));
10363#endif
10364 NC(nc_get_vara_float
10365 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
10366
10367 /* Read halos separately at boundaries... */
10368 float *help_halo;
10369 ALLOC(help_halo, float,
10370 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
10371 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
10372
10373#ifdef DD
10374 NC(nc_var_par_access(ncid, varid, NC_INDEPENDENT));
10375#endif
10376 if (dd->halo_bnd_count[1] > 0 && dd->halo_bnd_count[2] > 0
10377 && dd->halo_bnd_count[3] > 0) {
10378 NC(nc_get_vara_float
10379 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
10380 }
10381
10382 /* Check meteo data layout... */
10383 if (ctl->met_convention == 0) {
10384
10385 /* Copy and check data (ordering: lev, lat, lon)... */
10386 omp_set_dynamic(1);
10387#pragma omp parallel for default(shared)
10388 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10389 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10390 for (int ip = 0; ip < met->np; ip++) {
10391 const float aux =
10392 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
10393 (int) dd->subdomain_count[3])];
10394 if ((fillval == 0 || aux != fillval)
10395 && (missval == 0 || aux != missval)
10396 && fabsf(aux) < 1e14f) {
10397 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10398
10399 } else
10400 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10401 }
10402
10403#pragma omp parallel for default(shared)
10404 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10405 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10406 for (int ip = 0; ip < met->np; ip++) {
10407 const float aux =
10408 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
10409 (int) dd->halo_bnd_count[3])];
10410 if ((fillval == 0 || aux != fillval)
10411 && (missval == 0 || aux != missval)
10412 && fabsf(aux) < 1e14f)
10413 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10414 else
10415 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10416 }
10417 omp_set_dynamic(0);
10418
10419 } else {
10420
10421 /* Copy and check data (ordering: lon, lat, lev)... */
10422 omp_set_dynamic(1);
10423#pragma omp parallel for default(shared)
10424 for (int ip = 0; ip < met->np; ip++)
10425 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10426 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
10427 const float aux =
10428 help[ARRAY_3D
10429 (ix, iy, (int) dd->subdomain_count[2], ip, met->np)];
10430 if ((fillval == 0 || aux != fillval)
10431 && (missval == 0 || aux != missval)
10432 && fabsf(aux) < 1e14f)
10433 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10434 else
10435 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10436 }
10437
10438#pragma omp parallel for default(shared)
10439 for (int ip = 0; ip < met->np; ip++)
10440 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10441 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
10442 const float aux =
10443 help_halo[ARRAY_3D(ix, iy, (int) dd->halo_bnd_count[2], ip,
10444 met->np)];
10445 if ((fillval == 0 || aux != fillval)
10446 && (missval == 0 || aux != missval)
10447 && fabsf(aux) < 1e14f)
10448 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10449 else
10450 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10451 }
10452 omp_set_dynamic(0);
10453 }
10454
10455 /* Free... */
10456 free(help);
10457 free(help_halo);
10458 }
10459
10460 /* Return... */
10461 return 1;
10462}

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

10911 {
10912
10913 double aux[EP], p[EP];
10914
10915 /* Set timer... */
10916 SELECT_TIMER("READ_MET_ML2PL", "METPROC");
10917 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
10918
10919 /* Loop over columns... */
10920#pragma omp parallel for default(shared) private(aux,p) collapse(2)
10921 for (int ix = 0; ix < met->nx; ix++)
10922 for (int iy = 0; iy < met->ny; iy++) {
10923
10924 /* Copy pressure profile... */
10925 for (int ip = 0; ip < met->np; ip++)
10926 p[ip] = met->pl[ix][iy][ip];
10927
10928 /* Interpolate... */
10929 for (int ip = 0; ip < ctl->met_np; ip++) {
10930 double pt = ctl->met_p[ip];
10931 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
10932 pt = p[0];
10933 else if ((pt > p[met->np - 1] && p[1] > p[0])
10934 || (pt < p[met->np - 1] && p[1] < p[0]))
10935 pt = p[met->np - 1];
10936 const int ip2 = locate_irr(p, met->np, pt);
10937 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
10938 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
10939 }
10940
10941 /* Copy data... */
10942 for (int ip = 0; ip < ctl->met_np; ip++)
10943 var[ix][iy][ip] = (float) aux[ip];
10944 }
10945}
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 10949 of file mptrac.c.

10951 {
10952
10953 /* Check parameters... */
10954 if (ctl->advect_vert_coord != 1)
10955 return;
10956
10957 /* Set timer... */
10958 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC");
10959 LOG(2, "Make zeta profiles monotone...");
10960
10961 /* Create monotone zeta profiles... */
10962#pragma omp parallel for default(shared) collapse(2)
10963 for (int i = 0; i < met->nx; i++)
10964 for (int j = 0; j < met->ny; j++) {
10965 int k = 1;
10966
10967 while (k < met->npl) { /* Check if there is an inversion at level k... */
10968 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
10969 /* Find the upper level k+l over the inversion... */
10970 int l = 0;
10971 do {
10972 l++;
10973 }
10974 while ((met->zetal[i][j][k - 1] >=
10975 met->zetal[i][j][k + l]) & (k + l < met->npl));
10976
10977 /* Interpolate linear between the top and bottom
10978 of the inversion... */
10979 float s =
10980 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
10981 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
10982
10983 for (int m = k; m < k + l; m++) {
10984 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
10985 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
10986 }
10987
10988 /* Search for more inversions above the last inversion ... */
10989 k = k + l;
10990 } else {
10991 k++;
10992 }
10993 }
10994 }
10995
10996 /* Create monotone pressure profiles... */
10997#pragma omp parallel for default(shared) collapse(2)
10998 for (int i = 0; i < met->nx; i++)
10999 for (int j = 0; j < met->ny; j++) {
11000 int k = 1;
11001
11002 while (k < met->npl) { /* Check if there is an inversion at level k... */
11003 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
11004
11005 /* Find the upper level k+l over the inversion... */
11006 int l = 0;
11007 do {
11008 l++;
11009 }
11010 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
11011 met->npl));
11012
11013 /* Interpolate linear between the top and bottom
11014 of the inversion... */
11015 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
11016 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
11017
11018 for (int m = k; m < k + l; m++) {
11019 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
11020 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
11021 }
11022
11023 /* Search for more inversions above the last inversion ... */
11024 k += l;
11025 } else {
11026 k++;
11027 }
11028 }
11029 }
11030}

◆ read_met_nc()

int read_met_nc ( const char *  filename,
const ctl_t ctl,
met_t met,
dd_t dd 
)

Reads meteorological data from a NetCDF file and processes it.

This function reads meteorological data from a NetCDF file specified by the filename parameter, using the NetCDF library. It reads grid, surface, and vertical level data, processes the data (including extrapolation, boundary conditions, and downsampling), and calculates various derived meteorological fields such as geopotential heights, potential vorticity, cloud properties, and convective available potential energy (CAPE).

Parameters
filenameA constant character pointer representing the name of the NetCDF file to read the meteorological data from.
ctlA pointer to a ctl_t structure, which contains control parameters for reading and processing the meteorological data.
metA pointer to a met_t structure that will store the meteorological data read and processed from the NetCDF file.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.
Returns
Returns 1 on success, or 0 if the file cannot be opened.
Note
  • The function opens the NetCDF file in read-only mode using nc_open and handles any errors during the file opening process.
  • The function reads grid data, vertical level data, and surface data from the file, and processes the data to calculate additional meteorological parameters.
  • If the file cannot be opened, the function logs a warning and returns 0.
  • It is important to ensure that the NetCDF file contains the expected structure for meteorological data (grid, levels, surface data).
Author
Lars Hoffmann

Definition at line 11034 of file mptrac.c.

11038 {
11039
11040 int ncid;
11041
11042 /* Open file... */
11043#ifdef DD
11044 if (ctl->dd) {
11045 NC(nc_open_par
11046 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
11047 &ncid))
11048 }
11049#else
11050 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
11051 WARN("Cannot open file!");
11052 return 0;
11053 }
11054#endif
11055
11056 /* Set coordinate system of meteo data... */
11057 met->coord_type = ctl->met_coord_type;
11058
11059 /* Read coordinates of meteo data... */
11060 read_met_nc_grid(filename, ncid, ctl, met, dd);
11061
11062 /* Read surface data... */
11063 read_met_nc_surface(ncid, ctl, met, dd);
11064
11065 /* Read meteo data on vertical levels... */
11066 read_met_nc_levels(ncid, ctl, met, dd);
11067
11068 /* Close file... */
11069 NC(nc_close(ncid));
11070
11071 /* Return success... */
11072 return 1;
11073}
void read_met_nc_levels(const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads and processes meteorological level data from NetCDF files with domain decomposition.
Definition: mptrac.c:9639
void read_met_nc_surface(const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads and processes surface meteorological data from NetCDF files with domain decomposition.
Definition: mptrac.c:9501
void read_met_nc_grid(const char *filename, const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads meteorological grid data from NetCDF files with domain decomposition.
Definition: mptrac.c:9314
Here is the call graph for this function:

◆ dd_read_met_nc_grid()

void dd_read_met_nc_grid ( dd_t dd,
const ctl_t ctl,
met_t met,
const int  ncid 
)

Read meteorological grid information and construct the domain-decomposed grid with halo regions.

This routine reads the global longitude and latitude grid from a NetCDF meteorological input file and initializes the domain decomposition used for parallel processing. The global grid is partitioned into zonal and meridional subdomains according to ctl->dd_subdomains_zonal and ctl->dd_subdomains_meridional.

For the current MPI rank, the routine determines the core subdomain in index space and constructs a hyperslab describing the portion of the meteorological grid that must be read from the NetCDF file. The hyperslab is extended with inner halo cells to overlap with neighboring subdomains. For ranks located at the zonal boundaries, additional periodic boundary halos are created.

The function populates the local longitude and latitude arrays in the met_t structure for the subdomain including halos, and stores the hyperslab definitions and halo offsets in the dd_t structure.

Parameters
[out]ddDomain decomposition structure. On return it contains global grid dimensions, hyperslab definitions for the local subdomain, and halo metadata.
[in]ctlControl structure specifying the number of zonal and meridional subdomains and the halo size (dd_subdomains_zonal, dd_subdomains_meridional, dd_halos_size).
[out]metMeteorological grid structure. On return it contains the local longitude and latitude arrays and the grid dimensions (nx, ny, np) of the halo-extended subdomain.
[in]ncidNetCDF file identifier returned by nc_open().
Note
  • Requires MPI when compiled with -DMPI.
  • The domain decomposition is performed in index space; the global grid may therefore have irregular spacing (e.g. Gaussian latitudes).
  • Zonal periodicity is handled by constructing additional boundary halo hyperslabs with appropriate longitude shifts.
Author
Jan Clemens
Lars Hoffmann

Definition at line 11077 of file mptrac.c.

11081 {
11082
11083 int varid;
11084
11085 /* Get the MPI information... */
11086 int rank = 0, size = 1;
11087#ifdef MPI
11088 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
11089 MPI_Comm_size(MPI_COMM_WORLD, &size);
11090#endif
11091
11092 /* Get grid dimensions... */
11093 NC_INQ_DIM("lon", &dd->nx_glob, 0, 0, 0);
11094 NC_INQ_DIM("lat", &dd->ny_glob, 0, 0, 0);
11095
11096 LOG(2, "Number of longitudes: %d", dd->nx_glob);
11097 LOG(2, "Number of latitudes: %d", dd->ny_glob);
11098
11099 /* Check grid... */
11100 if (dd->nx_glob > DD_EX_GLOB || dd->ny_glob > DD_EY_GLOB)
11101 ERRMSG("Global grid is too large!");
11102
11103 if (ctl->dd_subdomains_zonal > dd->nx_glob)
11104 ERRMSG("Too many zonal subdomains for global x grid!");
11105
11106 if (ctl->dd_subdomains_meridional > dd->ny_glob)
11107 ERRMSG("Too many meridional subdomains for global y grid!");
11108
11109 /* Read global longitudes and latitudes... */
11110 NC_GET_DOUBLE("lon", dd->lon_glob, 1);
11111 NC_GET_DOUBLE("lat", dd->lat_glob, 1);
11112
11113 LOG(2, "Longitudes: %g, %g ... %g deg",
11114 dd->lon_glob[0], dd->lon_glob[1], dd->lon_glob[dd->nx_glob - 1]);
11115 LOG(2, "Latitudes: %g, %g ... %g deg",
11116 dd->lat_glob[0], dd->lat_glob[1], dd->lat_glob[dd->ny_glob - 1]);
11117
11118 /* Rank coordinates in DD layout... */
11119 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
11120 const int merid_rank = rank % ctl->dd_subdomains_meridional;
11121
11122 /* Check for edge cases... */
11123 const int left = (zonal_rank == 0);
11124 const int right = (zonal_rank == ctl->dd_subdomains_zonal - 1);
11125 const int top = (merid_rank == 0);
11126 const int bottom = (merid_rank == ctl->dd_subdomains_meridional - 1);
11127
11128 /* Core owned block (without halos)... */
11129 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
11130 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
11131
11132 const int ix0 = zonal_rank * nx_block;
11133 const int iy0 = merid_rank * ny_block;
11134
11135 int nx_core = nx_block;
11136 int ny_core = ny_block;
11137
11138 if (right)
11139 nx_core += dd->nx_glob - ctl->dd_subdomains_zonal * nx_block;
11140 if (bottom)
11141 ny_core += dd->ny_glob - ctl->dd_subdomains_meridional * ny_block;
11142
11143 /* Store core met size first... */
11144 met->nx = nx_core;
11145 met->ny = ny_core;
11146
11147 /* Set hyperslab for core subdomain... */
11148 dd->subdomain_start[0] = 0;
11149 dd->subdomain_start[1] = 0;
11150 dd->subdomain_start[2] = (size_t) iy0;
11151 dd->subdomain_start[3] = (size_t) ix0;
11152
11153 dd->subdomain_count[0] = 1;
11154 dd->subdomain_count[1] = (size_t) met->np;
11155 dd->subdomain_count[2] = (size_t) ny_core;
11156 dd->subdomain_count[3] = (size_t) nx_core;
11157
11158 /* Add inner halos to read window... */
11159 if (!left && !right) {
11160 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
11161 dd->subdomain_count[3] += (size_t) (2 * ctl->dd_halos_size);
11162 } else if (left ^ right) {
11163 dd->subdomain_count[3] += (size_t) ctl->dd_halos_size;
11164 if (!left)
11165 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
11166 }
11167
11168 if (!top && !bottom) {
11169 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
11170 dd->subdomain_count[2] += (size_t) (2 * ctl->dd_halos_size);
11171 } else if (top ^ bottom) {
11172 dd->subdomain_count[2] += (size_t) ctl->dd_halos_size;
11173 if (!top)
11174 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
11175 }
11176
11177 /* Set boundary halo hyperslabs... */
11178 double lon_shift = 0.0;
11179
11180 if (left ^ right) {
11181 dd->halo_bnd_start[0] = 0;
11182 dd->halo_bnd_start[1] = 0;
11183 dd->halo_bnd_start[2] = dd->subdomain_start[2];
11184 dd->halo_bnd_start[3] =
11185 (size_t) (left ? (dd->nx_glob - ctl->dd_halos_size) : 0);
11186
11187 dd->halo_bnd_count[0] = 1;
11188 dd->halo_bnd_count[1] = (size_t) met->np;
11189 dd->halo_bnd_count[2] =
11190 (size_t) met->ny +
11191 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
11192 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
11193
11194 dd->halo_offset_start = left ? (int) dd->halo_bnd_count[3] : 0;
11195 dd->halo_offset_end = left ? 0 : (int) dd->subdomain_count[3];
11196 lon_shift = left ? -360.0 : 360.0;
11197 } else {
11198 dd->halo_bnd_start[0] = 0;
11199 dd->halo_bnd_start[1] = 0;
11200 dd->halo_bnd_start[2] = 0;
11201 dd->halo_bnd_start[3] = 0;
11202
11203 dd->halo_bnd_count[0] = 0;
11204 dd->halo_bnd_count[1] = 0;
11205 dd->halo_bnd_count[2] = 0;
11206 dd->halo_bnd_count[3] = 0;
11207
11208 dd->halo_offset_start = 0;
11209 dd->halo_offset_end = 0;
11210 }
11211
11212 /* Focus on subdomain latitudes... */
11213 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
11214 met->lat[iy] = dd->lat_glob[(int) dd->subdomain_start[2] + iy];
11215
11216 /* Focus on subdomain longitudes... */
11217 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
11218 met->lon[ix + dd->halo_offset_start] =
11219 dd->lon_glob[(int) dd->subdomain_start[3] + ix];
11220
11221 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
11222 met->lon[ix + dd->halo_offset_end] =
11223 dd->lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
11224
11225 /* Reset halo-extended grid dimensions... */
11226 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
11227 met->ny = (int) dd->subdomain_count[2];
11228
11229 LOG(2, "Define subdomain properties.");
11230 LOG(2, "MPI information: Rank %d, Size %d", rank, size);
11231 LOG(2, "Edge position: l=%d,r=%d,t=%d,b=%d", left, right, top, bottom);
11232 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d",
11233 met->nx, met->ny, met->np);
11234 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
11235 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
11236 (int) dd->halo_bnd_count[1]);
11237 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
11238 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
11239 (int) dd->subdomain_count[1]);
11240 LOG(2, "Subdomain start: nx %ld ny %ld np %ld",
11241 dd->subdomain_start[3], dd->subdomain_start[2], dd->subdomain_start[1]);
11242 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld",
11243 dd->halo_bnd_start[3], dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
11244 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
11245 LOG(2, "%d Subdomain longitudes: %g, %g ... %g deg",
11246 rank, met->lon[0], met->lon[1], met->lon[met->nx - 1]);
11247 LOG(2, "%d Subdomain latitudes: %g, %g ... %g deg",
11248 rank, met->lat[0], met->lat[1], met->lat[met->ny - 1]);
11249}
#define DD_EY_GLOB
Maximum number of latitudes of global meteo data.
Definition: mptrac.h:424
#define DD_EX_GLOB
Maximum number of longitudes of global meteo data.
Definition: mptrac.h:419
int nx_glob
Number of global longitudes.
Definition: mptrac.h:3779
double lon_glob[DD_EX_GLOB]
Longitudes of the global grid [deg].
Definition: mptrac.h:3785
double lat_glob[DD_EY_GLOB]
Latitudes of the global grid [deg].
Definition: mptrac.h:3788
int ny_glob
Number of global latitudes.
Definition: mptrac.h:3782

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

11255 {
11256
11257 /* Set timer... */
11258 SELECT_TIMER("READ_MET_PBL", "METPROC");
11259 LOG(2, "Calculate planetary boundary layer...");
11260
11261 /* Convert PBL height from meteo file to pressure... */
11262 if (ctl->met_pbl == 1) {
11263
11264 /* Loop over grid points... */
11265#pragma omp parallel for default(shared) collapse(2)
11266 for (int ix = 0; ix < met->nx; ix++)
11267 for (int iy = 0; iy < met->ny; iy++) {
11268
11269 /* Get pressure at top of PBL... */
11270 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
11271 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
11272 met->pbl[ix][iy] =
11273 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
11274 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
11275 }
11276 }
11277
11278 /* Determine PBL based on Richardson number... */
11279 else if (ctl->met_pbl == 2) {
11280
11281 /* Parameters used to estimate the height of the PBL
11282 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
11283 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
11284
11285 /* Loop over grid points... */
11286#pragma omp parallel for default(shared) collapse(2)
11287 for (int ix = 0; ix < met->nx; ix++)
11288 for (int iy = 0; iy < met->ny; iy++) {
11289
11290 /* Set bottom level of PBL... */
11291 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
11292
11293 /* Find lowest level near the bottom... */
11294 int ip;
11295 for (ip = 1; ip < met->np; ip++)
11296 if (met->p[ip] < pbl_bot)
11297 break;
11298
11299 /* Get near surface data... */
11300 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
11301 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
11302 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
11303
11304 /* Init... */
11305 double rib_old = 0;
11306
11307 /* Loop over levels... */
11308 for (; ip < met->np; ip++) {
11309
11310 /* Get squared horizontal wind speed... */
11311 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
11312 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
11313 vh2 = MAX(vh2, SQR(umin));
11314
11315 /* Calculate bulk Richardson number... */
11316 const double rib =
11317 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
11318 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
11319 met->h2o[ix][iy][ip]) - tvs) / vh2;
11320
11321 /* Check for critical value... */
11322 if (rib >= rib_crit) {
11323 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
11324 rib, met->p[ip], rib_crit));
11325 if (met->pbl[ix][iy] > pbl_bot)
11326 met->pbl[ix][iy] = (float) pbl_bot;
11327 break;
11328 }
11329
11330 /* Save Richardson number... */
11331 rib_old = rib;
11332 }
11333 }
11334 }
11335
11336 /* Determine PBL based on potential temperature... */
11337 if (ctl->met_pbl == 3) {
11338
11339 /* Parameters used to estimate the height of the PBL
11340 (following HYSPLIT model)... */
11341 const double dtheta = 2.0, zmin = 0.1;
11342
11343 /* Loop over grid points... */
11344#pragma omp parallel for default(shared) collapse(2)
11345 for (int ix = 0; ix < met->nx; ix++)
11346 for (int iy = 0; iy < met->ny; iy++) {
11347
11348 /* Potential temperature at the surface... */
11349 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
11350
11351 /* Find topmost level where theta exceeds surface value by 2 K... */
11352 int ip;
11353 for (ip = met->np - 2; ip > 0; ip--)
11354 if (met->p[ip] >= 300.)
11355 if (met->p[ip] > met->ps[ix][iy]
11356 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
11357 break;
11358
11359 /* Interpolate... */
11360 met->pbl[ix][iy]
11361 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
11362 met->p[ip + 1],
11363 THETA(met->p[ip], met->t[ix][iy][ip]),
11364 met->p[ip], theta0 + dtheta));
11365
11366 /* Check minimum value... */
11367 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
11368 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
11369 met->pbl[ix][iy] = (float) pbl_min;
11370 }
11371 }
11372
11373 /* Loop over grid points... */
11374#pragma omp parallel for default(shared) collapse(2)
11375 for (int ix = 0; ix < met->nx; ix++)
11376 for (int iy = 0; iy < met->ny; iy++) {
11377
11378 /* Check minimum value... */
11379 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
11380 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
11381
11382 /* Check maximum value... */
11383 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
11384 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
11385 }
11386}
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 11390 of file mptrac.c.

11391 {
11392
11393 /* Set timer... */
11394 SELECT_TIMER("READ_MET_PERIODIC", "METPROC");
11395 LOG(2, "Apply periodic boundary conditions...");
11396
11397 /* Check longitudes... */
11398 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
11399 + met->lon[1] - met->lon[0] - 360) < 0.01))
11400 return;
11401
11402 /* Increase longitude counter... */
11403 if ((++met->nx) >= EX)
11404 ERRMSG("Cannot create periodic boundary conditions!");
11405
11406 /* Set longitude... */
11407 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
11408
11409 /* Loop over latitudes and pressure levels... */
11410#pragma omp parallel for default(shared)
11411 for (int iy = 0; iy < met->ny; iy++) {
11412 met->ps[met->nx - 1][iy] = met->ps[0][iy];
11413 met->zs[met->nx - 1][iy] = met->zs[0][iy];
11414 met->ts[met->nx - 1][iy] = met->ts[0][iy];
11415 met->us[met->nx - 1][iy] = met->us[0][iy];
11416 met->vs[met->nx - 1][iy] = met->vs[0][iy];
11417 met->ess[met->nx - 1][iy] = met->ess[0][iy];
11418 met->nss[met->nx - 1][iy] = met->nss[0][iy];
11419 met->shf[met->nx - 1][iy] = met->shf[0][iy];
11420 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
11421 met->sst[met->nx - 1][iy] = met->sst[0][iy];
11422 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
11423 met->cape[met->nx - 1][iy] = met->cape[0][iy];
11424 met->cin[met->nx - 1][iy] = met->cin[0][iy];
11425 for (int ip = 0; ip < met->np; ip++) {
11426 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
11427 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
11428 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
11429 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
11430 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
11431 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
11432 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
11433 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
11434 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
11435 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
11436 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
11437 }
11438 for (int ip = 0; ip < met->npl; ip++) {
11439 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
11440 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
11441 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
11442 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
11443 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
11444 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
11445 }
11446 }
11447}

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

11452 {
11453
11454 /* Set timer... */
11455 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC");
11456 LOG(2, "Apply fix for polar winds...");
11457
11458 if (met->coord_type != 0)
11459 return;
11460
11461 /* Check latitudes... */
11462 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
11463 return;
11464
11465 /* Loop over hemispheres... */
11466 for (int ihem = 0; ihem < 2; ihem++) {
11467
11468 /* Set latitude indices... */
11469 int i89 = 1, i90 = 0, sign = 1;
11470 if (ihem == 1) {
11471 i89 = met->ny - 2;
11472 i90 = met->ny - 1;
11473 }
11474 if (met->lat[i90] < 0)
11475 sign = -1;
11476
11477 /* Look-up table of cosinus and sinus... */
11478 double clon[EX], slon[EX];
11479#pragma omp parallel for default(shared)
11480 for (int ix = 0; ix < met->nx; ix++) {
11481 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
11482 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
11483 }
11484
11485 /* Loop over levels... */
11486#pragma omp parallel for default(shared)
11487 for (int ip = 0; ip < met->np; ip++) {
11488
11489 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
11490 double vel89x = 0, vel89y = 0;
11491 for (int ix = 0; ix < met->nx; ix++) {
11492 vel89x +=
11493 (met->u[ix][i89][ip] * clon[ix] -
11494 met->v[ix][i89][ip] * slon[ix]) / met->nx;
11495 vel89y +=
11496 (met->u[ix][i89][ip] * slon[ix] +
11497 met->v[ix][i89][ip] * clon[ix]) / met->nx;
11498 }
11499
11500 /* Replace 90 degree winds by 89 degree mean... */
11501 for (int ix = 0; ix < met->nx; ix++) {
11502 met->u[ix][i90][ip]
11503 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
11504 met->v[ix][i90][ip]
11505 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
11506 }
11507 }
11508 }
11509}

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

11514 {
11515
11516 double pows[EP];
11517
11518 /* Set timer... */
11519 SELECT_TIMER("READ_MET_PV", "METPROC");
11520 LOG(2, "Calculate potential vorticity...");
11521
11522 /* Set powers... */
11523#pragma omp parallel for default(shared)
11524 for (int ip = 0; ip < met->np; ip++)
11525 pows[ip] = pow(1000. / met->p[ip], 0.286);
11526
11527 /* Loop over grid points... */
11528#pragma omp parallel for default(shared)
11529 for (int ix = 0; ix < met->nx; ix++) {
11530
11531 /* Set indices... */
11532 const int ix0 = MAX(ix - 1, 0);
11533 const int ix1 = MIN(ix + 1, met->nx - 1);
11534
11535 /* Loop over grid points... */
11536 for (int iy = 0; iy < met->ny; iy++) {
11537
11538 /* Set indices... */
11539 const int iy0 = MAX(iy - 1, 0);
11540 const int iy1 = MIN(iy + 1, met->ny - 1);
11541
11542 /* Set auxiliary variables... */
11543 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
11544 double dx, dy, c0, c1, cr, vort;
11545
11546 // Calculate potential vorticity..
11547 if (met->coord_type == 0) { // coords are lat/lon
11548 dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
11549 dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
11550 c0 = cos(DEG2RAD(met->lat[iy0]));
11551 c1 = cos(DEG2RAD(met->lat[iy1]));
11552 cr = cos(DEG2RAD(latr));
11553 vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
11554 } else { // coords are in meters
11555 dx = met->lon[ix1] - met->lon[ix0];
11556 dy = met->lat[iy1] - met->lat[iy0];
11557
11558 c0 = 1.0;
11559 c1 = 1.0;
11560 cr = 1.0;
11561
11562 vort = 2 * 7.2921e-5 * sin(latr / (RE * 1000));
11563 }
11564
11565 /* Loop over grid points... */
11566 for (int ip = 0; ip < met->np; ip++) {
11567
11568 /* Get gradients in longitude... */
11569 const double dtdx
11570 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
11571 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
11572
11573 /* Get gradients in latitude... */
11574 const double dtdy
11575 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
11576 const double dudy
11577 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
11578
11579 /* Set indices... */
11580 const int ip0 = MAX(ip - 1, 0);
11581 const int ip1 = MIN(ip + 1, met->np - 1);
11582
11583 /* Get gradients in pressure... */
11584 double dtdp, dudp, dvdp;
11585 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
11586 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
11587 if (ip != ip0 && ip != ip1) {
11588 double denom = dp0 * dp1 * (dp0 + dp1);
11589 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
11590 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
11591 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
11592 / denom;
11593 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
11594 - dp1 * dp1 * met->u[ix][iy][ip0]
11595 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
11596 / denom;
11597 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
11598 - dp1 * dp1 * met->v[ix][iy][ip0]
11599 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
11600 / denom;
11601 } else {
11602 const double denom = dp0 + dp1;
11603 dtdp =
11604 (met->t[ix][iy][ip1] * pows[ip1] -
11605 met->t[ix][iy][ip0] * pows[ip0]) / denom;
11606 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
11607 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
11608 }
11609
11610 /* Calculate PV... */
11611 met->pv[ix][iy][ip] = (float)
11612 (1e6 * G0 *
11613 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
11614 }
11615 }
11616 }
11617
11618 /* Fix for polar regions... */
11619#pragma omp parallel for default(shared)
11620 for (int ix = 0; ix < met->nx; ix++)
11621 for (int ip = 0; ip < met->np; ip++) {
11622 met->pv[ix][0][ip]
11623 = met->pv[ix][1][ip]
11624 = met->pv[ix][2][ip];
11625 met->pv[ix][met->ny - 1][ip]
11626 = met->pv[ix][met->ny - 2][ip]
11627 = met->pv[ix][met->ny - 3][ip];
11628 }
11629}
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:630
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:609

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

11634 {
11635
11636 /* Set timer... */
11637 SELECT_TIMER("READ_MET_OZONE", "METPROC");
11638 LOG(2, "Calculate total column ozone...");
11639
11640 /* Loop over columns... */
11641#pragma omp parallel for default(shared) collapse(2)
11642 for (int ix = 0; ix < met->nx; ix++)
11643 for (int iy = 0; iy < met->ny; iy++) {
11644
11645 /* Integrate... */
11646 double cd = 0;
11647 for (int ip = 1; ip < met->np; ip++)
11648 if (met->p[ip - 1] <= met->ps[ix][iy]) {
11649 const double vmr =
11650 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
11651 const double dp = met->p[ip - 1] - met->p[ip];
11652 cd += vmr * MO3 / MA * dp * 1e2 / G0;
11653 }
11654
11655 /* Convert to Dobson units... */
11656 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
11657 }
11658}

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

11664 {
11665
11666 met_t *help;
11667
11668 /* Check parameters... */
11669 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
11670 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
11671 return;
11672
11673 /* Set timer... */
11674 SELECT_TIMER("READ_MET_SAMPLE", "METPROC");
11675 LOG(2, "Downsampling of meteo data...");
11676
11677 /* Allocate... */
11678 ALLOC(help, met_t, 1);
11679
11680 /* Copy data... */
11681 help->nx = met->nx;
11682 help->ny = met->ny;
11683 help->np = met->np;
11684 memcpy(help->lon, met->lon, sizeof(met->lon));
11685 memcpy(help->lat, met->lat, sizeof(met->lat));
11686 memcpy(help->p, met->p, sizeof(met->p));
11687
11688 /* Smoothing... */
11689 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
11690 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
11691 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
11692 help->ps[ix][iy] = 0;
11693 help->zs[ix][iy] = 0;
11694 help->ts[ix][iy] = 0;
11695 help->us[ix][iy] = 0;
11696 help->vs[ix][iy] = 0;
11697 help->ess[ix][iy] = 0;
11698 help->nss[ix][iy] = 0;
11699 help->shf[ix][iy] = 0;
11700 help->lsm[ix][iy] = 0;
11701 help->sst[ix][iy] = 0;
11702 help->pbl[ix][iy] = 0;
11703 help->cape[ix][iy] = 0;
11704 help->cin[ix][iy] = 0;
11705 help->t[ix][iy][ip] = 0;
11706 help->u[ix][iy][ip] = 0;
11707 help->v[ix][iy][ip] = 0;
11708 help->w[ix][iy][ip] = 0;
11709 help->h2o[ix][iy][ip] = 0;
11710 help->o3[ix][iy][ip] = 0;
11711 help->lwc[ix][iy][ip] = 0;
11712 help->rwc[ix][iy][ip] = 0;
11713 help->iwc[ix][iy][ip] = 0;
11714 help->swc[ix][iy][ip] = 0;
11715 help->cc[ix][iy][ip] = 0;
11716 float wsum = 0;
11717 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
11718 ix2++) {
11719 int ix3 = ix2;
11720 if (ix3 < 0)
11721 ix3 += met->nx;
11722 else if (ix3 >= met->nx)
11723 ix3 -= met->nx;
11724
11725 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
11726 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
11727 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
11728 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
11729 const float w =
11730 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
11731 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
11732 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
11733 help->ps[ix][iy] += w * met->ps[ix3][iy2];
11734 help->zs[ix][iy] += w * met->zs[ix3][iy2];
11735 help->ts[ix][iy] += w * met->ts[ix3][iy2];
11736 help->us[ix][iy] += w * met->us[ix3][iy2];
11737 help->vs[ix][iy] += w * met->vs[ix3][iy2];
11738 help->ess[ix][iy] += w * met->ess[ix3][iy2];
11739 help->nss[ix][iy] += w * met->nss[ix3][iy2];
11740 help->shf[ix][iy] += w * met->shf[ix3][iy2];
11741 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
11742 help->sst[ix][iy] += w * met->sst[ix3][iy2];
11743 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
11744 help->cape[ix][iy] += w * met->cape[ix3][iy2];
11745 help->cin[ix][iy] += w * met->cin[ix3][iy2];
11746 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
11747 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
11748 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
11749 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
11750 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
11751 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
11752 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
11753 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
11754 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
11755 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
11756 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
11757 wsum += w;
11758 }
11759 }
11760 help->ps[ix][iy] /= wsum;
11761 help->zs[ix][iy] /= wsum;
11762 help->ts[ix][iy] /= wsum;
11763 help->us[ix][iy] /= wsum;
11764 help->vs[ix][iy] /= wsum;
11765 help->ess[ix][iy] /= wsum;
11766 help->nss[ix][iy] /= wsum;
11767 help->shf[ix][iy] /= wsum;
11768 help->lsm[ix][iy] /= wsum;
11769 help->sst[ix][iy] /= wsum;
11770 help->pbl[ix][iy] /= wsum;
11771 help->cape[ix][iy] /= wsum;
11772 help->cin[ix][iy] /= wsum;
11773 help->t[ix][iy][ip] /= wsum;
11774 help->u[ix][iy][ip] /= wsum;
11775 help->v[ix][iy][ip] /= wsum;
11776 help->w[ix][iy][ip] /= wsum;
11777 help->h2o[ix][iy][ip] /= wsum;
11778 help->o3[ix][iy][ip] /= wsum;
11779 help->lwc[ix][iy][ip] /= wsum;
11780 help->rwc[ix][iy][ip] /= wsum;
11781 help->iwc[ix][iy][ip] /= wsum;
11782 help->swc[ix][iy][ip] /= wsum;
11783 help->cc[ix][iy][ip] /= wsum;
11784 }
11785 }
11786 }
11787
11788 /* Downsampling... */
11789 met->nx = 0;
11790 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
11791 met->lon[met->nx] = help->lon[ix];
11792 met->ny = 0;
11793 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
11794 met->lat[met->ny] = help->lat[iy];
11795 met->ps[met->nx][met->ny] = help->ps[ix][iy];
11796 met->zs[met->nx][met->ny] = help->zs[ix][iy];
11797 met->ts[met->nx][met->ny] = help->ts[ix][iy];
11798 met->us[met->nx][met->ny] = help->us[ix][iy];
11799 met->vs[met->nx][met->ny] = help->vs[ix][iy];
11800 met->ess[met->nx][met->ny] = help->ess[ix][iy];
11801 met->nss[met->nx][met->ny] = help->nss[ix][iy];
11802 met->shf[met->nx][met->ny] = help->shf[ix][iy];
11803 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
11804 met->sst[met->nx][met->ny] = help->sst[ix][iy];
11805 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
11806 met->cape[met->nx][met->ny] = help->cape[ix][iy];
11807 met->cin[met->nx][met->ny] = help->cin[ix][iy];
11808 met->np = 0;
11809 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
11810 met->p[met->np] = help->p[ip];
11811 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
11812 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
11813 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
11814 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
11815 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
11816 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
11817 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
11818 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
11819 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
11820 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
11821 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
11822 met->np++;
11823 }
11824 met->ny++;
11825 }
11826 met->nx++;
11827 }
11828
11829 /* Free... */
11830 free(help);
11831}

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

11838 {
11839
11840 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
11841 th2[200], z[EP], z2[200];
11842
11843 /* Set timer... */
11844 SELECT_TIMER("READ_MET_TROPO", "METPROC");
11845 LOG(2, "Calculate tropopause...");
11846
11847 /* Get altitude and pressure profiles... */
11848#pragma omp parallel for default(shared)
11849 for (int iz = 0; iz < met->np; iz++)
11850 z[iz] = Z(met->p[iz]);
11851#pragma omp parallel for default(shared)
11852 for (int iz = 0; iz <= 190; iz++) {
11853 z2[iz] = 4.5 + 0.1 * iz;
11854 p2[iz] = P(z2[iz]);
11855 }
11856
11857 /* Do not calculate tropopause... */
11858 if (ctl->met_tropo == 0)
11859#pragma omp parallel for default(shared) collapse(2)
11860 for (int ix = 0; ix < met->nx; ix++)
11861 for (int iy = 0; iy < met->ny; iy++)
11862 met->pt[ix][iy] = NAN;
11863
11864 /* Use tropopause climatology... */
11865 else if (ctl->met_tropo == 1) {
11866 if (met->coord_type != 0)
11867 ERRMSG("Only lat/lon grid supported");
11868#pragma omp parallel for default(shared) collapse(2)
11869 for (int ix = 0; ix < met->nx; ix++)
11870 for (int iy = 0; iy < met->ny; iy++)
11871 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
11872 }
11873
11874 /* Use cold point... */
11875 else if (ctl->met_tropo == 2) {
11876
11877 /* Loop over grid points... */
11878#pragma omp parallel for default(shared) private(t,t2) collapse(2)
11879 for (int ix = 0; ix < met->nx; ix++)
11880 for (int iy = 0; iy < met->ny; iy++) {
11881
11882 /* Interpolate temperature profile... */
11883 for (int iz = 0; iz < met->np; iz++)
11884 t[iz] = met->t[ix][iy][iz];
11885 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
11886
11887 /* Find minimum... */
11888 int iz = (int) gsl_stats_min_index(t2, 1, 171);
11889 if (iz > 0 && iz < 170)
11890 met->pt[ix][iy] = (float) p2[iz];
11891 else
11892 met->pt[ix][iy] = NAN;
11893 }
11894 }
11895
11896 /* Use WMO definition... */
11897 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
11898
11899 /* Loop over grid points... */
11900#pragma omp parallel for default(shared) private(t,t2) collapse(2)
11901 for (int ix = 0; ix < met->nx; ix++)
11902 for (int iy = 0; iy < met->ny; iy++) {
11903
11904 /* Interpolate temperature profile... */
11905 int iz;
11906 for (iz = 0; iz < met->np; iz++)
11907 t[iz] = met->t[ix][iy][iz];
11908 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
11909
11910 /* Find 1st tropopause... */
11911 met->pt[ix][iy] = NAN;
11912 for (iz = 0; iz <= 170; iz++) {
11913 int found = 1;
11914 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
11915 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
11916 found = 0;
11917 break;
11918 }
11919 if (found) {
11920 if (iz > 0 && iz < 170)
11921 met->pt[ix][iy] = (float) p2[iz];
11922 break;
11923 }
11924 }
11925
11926 /* Find 2nd tropopause... */
11927 if (ctl->met_tropo == 4) {
11928 met->pt[ix][iy] = NAN;
11929 for (; iz <= 170; iz++) {
11930 int found = 1;
11931 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
11932 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
11933 found = 0;
11934 break;
11935 }
11936 if (found)
11937 break;
11938 }
11939 for (; iz <= 170; iz++) {
11940 int found = 1;
11941 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
11942 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
11943 found = 0;
11944 break;
11945 }
11946 if (found) {
11947 if (iz > 0 && iz < 170)
11948 met->pt[ix][iy] = (float) p2[iz];
11949 break;
11950 }
11951 }
11952 }
11953 }
11954 }
11955
11956 /* Use dynamical tropopause... */
11957 else if (ctl->met_tropo == 5) {
11958
11959 /* Loop over grid points... */
11960#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
11961 for (int ix = 0; ix < met->nx; ix++)
11962 for (int iy = 0; iy < met->ny; iy++) {
11963
11964 /* Interpolate potential vorticity profile... */
11965 for (int iz = 0; iz < met->np; iz++)
11966 pv[iz] = met->pv[ix][iy][iz];
11967 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
11968
11969 /* Interpolate potential temperature profile... */
11970 for (int iz = 0; iz < met->np; iz++)
11971 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
11972 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
11973
11974 /* Find dynamical tropopause... */
11975 met->pt[ix][iy] = NAN;
11976 for (int iz = 0; iz <= 170; iz++)
11977 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
11978 || th2[iz] >= ctl->met_tropo_theta) {
11979 if (iz > 0 && iz < 170)
11980 met->pt[ix][iy] = (float) p2[iz];
11981 break;
11982 }
11983 }
11984 }
11985
11986 else
11987 ERRMSG("Cannot calculate tropopause!");
11988
11989 /* Interpolate temperature, geopotential height, and water vapor... */
11990#pragma omp parallel for default(shared) collapse(2)
11991 for (int ix = 0; ix < met->nx; ix++)
11992 for (int iy = 0; iy < met->ny; iy++) {
11993 double h2ot, tt, zt;
11995 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
11996 met->lat[iy], &tt, ci, cw, 1);
11997 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
11998 met->lat[iy], &zt, ci, cw, 0);
11999 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
12000 met->lat[iy], &h2ot, ci, cw, 0);
12001 met->tt[ix][iy] = (float) tt;
12002 met->zt[ix][iy] = (float) zt;
12003 met->h2ot[ix][iy] = (float) h2ot;
12004 }
12005}
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:12215
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:1122
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 12009 of file mptrac.c.

12017 {
12018
12019 /* Write info... */
12020 LOG(1, "Read observation data: %s", filename);
12021
12022 /* Read data... */
12023 if (ctl->obs_type == 0)
12024 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
12025 else if (ctl->obs_type == 1)
12026 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
12027 else
12028 ERRMSG("Set OBS_TYPE to 0 or 1!");
12029
12030 /* Check time... */
12031 for (int i = 1; i < *nobs; i++)
12032 if (rt[i] < rt[i - 1])
12033 ERRMSG("Time must be ascending!");
12034
12035 /* Write info... */
12036 int n = *nobs;
12037 double mini, maxi;
12038 LOG(2, "Number of observations: %d", *nobs);
12039 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
12040 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
12041 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
12042 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
12043 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
12044 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
12045 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
12046 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
12047 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
12048 LOG(2, "Observation range: %g ... %g", mini, maxi);
12049}
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:12053
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:12081
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 12053 of file mptrac.c.

12060 {
12061
12062 /* Open observation data file... */
12063 FILE *in;
12064 if (!(in = fopen(filename, "r")))
12065 ERRMSG("Cannot open file!");
12066
12067 /* Read observations... */
12068 char line[LEN];
12069 while (fgets(line, LEN, in))
12070 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
12071 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
12072 if ((++(*nobs)) >= NOBS)
12073 ERRMSG("Too many observations!");
12074
12075 /* Close observation data file... */
12076 fclose(in);
12077}
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:379

◆ read_obs_nc()

void read_obs_nc ( const char *  filename,
double *  rt,
double *  rz,
double *  rlon,
double *  rlat,
double *  robs,
int *  nobs 
)

Reads observation data from a NetCDF file.

This function reads observation data from a specified NetCDF file. It extracts time, altitude, longitude, latitude, and observation values from the variables in the NetCDF file and stores them in the provided arrays.

Parameters
filenameThe path to the NetCDF file containing the observation data.
rtAn array to store the time values of the observations.
rzAn array to store the altitude values of the observations.
rlonAn array to store the longitude values of the observations.
rlatAn array to store the latitude values of the observations.
robsAn array to store the observation values.
nobsA pointer to an integer variable to store the number of observations read.

The function performs the following steps:

  • Attempts to open the specified NetCDF file in read-only mode using the nc_open function.
  • Queries the dimensions of the 'nobs' variable in the NetCDF file to determine the number of observations using the NC_INQ_DIM macro.
  • Reads the 'time', 'alt', 'lon', 'lat', and 'obs' variables from the NetCDF file using the NC_GET_DOUBLE macro and stores them in the respective arrays.
  • Closes the NetCDF file after reading all data using the nc_close function.
Note
The function assumes that the NetCDF file contains the required variables ('time', 'alt', 'lon', 'lat', 'obs') and that the arrays provided have sufficient memory allocated to store the data.
Author
Lars Hoffmann

Definition at line 12081 of file mptrac.c.

12088 {
12089
12090 int ncid, varid;
12091
12092 /* Open netCDF file... */
12093 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
12094 ERRMSG("Cannot open file!");
12095
12096 /* Read the observations from the NetCDF file... */
12097 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
12098 NC_GET_DOUBLE("time", rt, 1);
12099 NC_GET_DOUBLE("alt", rz, 1);
12100 NC_GET_DOUBLE("lon", rlon, 1);
12101 NC_GET_DOUBLE("lat", rlat, 1);
12102 NC_GET_DOUBLE("obs", robs, 1);
12103
12104 /* Close file... */
12105 NC(nc_close(ncid));
12106}

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

12117 {
12118
12119 FILE *in = NULL;
12120
12121 char fullname1[LEN], fullname2[LEN], rval[LEN];
12122
12123 int contain = 0, i;
12124
12125 /* Open file... */
12126 if (filename[strlen(filename) - 1] != '-')
12127 if (!(in = fopen(filename, "r")))
12128 ERRMSG("Cannot open file!");
12129
12130 /* Set full variable name... */
12131 if (arridx >= 0) {
12132 sprintf(fullname1, "%s[%d]", varname, arridx);
12133 sprintf(fullname2, "%s[*]", varname);
12134 } else {
12135 sprintf(fullname1, "%s", varname);
12136 sprintf(fullname2, "%s", varname);
12137 }
12138
12139 /* Read data... */
12140 if (in != NULL) {
12141 char dummy[LEN], line[LEN], rvarname[LEN];
12142 while (fgets(line, LEN, in)) {
12143 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
12144 if (strcasecmp(rvarname, fullname1) == 0 ||
12145 strcasecmp(rvarname, fullname2) == 0) {
12146 contain = 1;
12147 break;
12148 }
12149 }
12150 }
12151 for (i = 1; i < argc - 1; i++)
12152 if (strcasecmp(argv[i], fullname1) == 0 ||
12153 strcasecmp(argv[i], fullname2) == 0) {
12154 sprintf(rval, "%s", argv[i + 1]);
12155 contain = 1;
12156 break;
12157 }
12158
12159 /* Close file... */
12160 if (in != NULL)
12161 fclose(in);
12162
12163 /* Check for missing variables... */
12164 if (!contain) {
12165 if (strlen(defvalue) > 0)
12166 sprintf(rval, "%s", defvalue);
12167 else
12168 ERRMSG("Missing variable %s!\n", fullname1);
12169 }
12170
12171 /* Write info... */
12172 LOG(1, "%s = %s", fullname1, rval);
12173
12174 /* Return values... */
12175 if (value != NULL)
12176 sprintf(value, "%s", rval);
12177 return atof(rval);
12178}

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

12186 {
12187
12188 /* Convert particle radius from microns to m... */
12189 const double rp_help = rp * 1e-6;
12190
12191 /* Density of dry air [kg / m^3]... */
12192 const double rho = RHO(p, T);
12193
12194 /* Dynamic viscosity of air [kg / (m s)]... */
12195 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
12196
12197 /* Thermal velocity of an air molecule [m / s]... */
12198 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
12199
12200 /* Mean free path of an air molecule [m]... */
12201 const double lambda = 2. * eta / (rho * v);
12202
12203 /* Knudsen number for air (dimensionless)... */
12204 const double K = lambda / rp_help;
12205
12206 /* Cunningham slip-flow correction (dimensionless)... */
12207 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
12208
12209 /* Sedimentation velocity [m / s]... */
12210 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
12211}
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:285

◆ spline()

void spline ( const double *  x,
const double *  y,
const int  n,
const double *  x2,
double *  y2,
const int  n2,
const int  method 
)

Performs spline interpolation or linear interpolation.

This function interpolates a set of data points using either cubic spline interpolation or linear interpolation, depending on the specified method.

Parameters
xThe array of x-coordinates of the data points.
yThe array of y-coordinates of the data points.
nThe number of data points.
x2The array of x-coordinates where interpolation is required.
y2The array to store the interpolated y-values.
n2The number of points to interpolate.
methodThe interpolation method: 1 for cubic spline, 0 for linear interpolation.

If the method is set to 1 (cubic spline interpolation):

  • The function initializes a cubic spline interpolator using GSL.
  • It interpolates the y-values at the specified x-coordinates using the spline.
  • The interpolated y-values are stored in the provided y2 array.

If the method is set to 0 (linear interpolation):

  • The function performs linear interpolation between adjacent data points.
  • It locates the interval where each interpolation point falls and calculates the interpolated y-value using linear interpolation.
  • The interpolated y-values are stored in the provided y2 array.
Note
The x-coordinates in both arrays (x and x2) must be sorted in ascending order.
Author
Lars Hoffmann

Definition at line 12215 of file mptrac.c.

12222 {
12223
12224 /* Cubic spline interpolation... */
12225 if (method == 1) {
12226
12227 /* Allocate... */
12228 gsl_interp_accel *acc = gsl_interp_accel_alloc();
12229 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
12230
12231 /* Interpolate profile... */
12232 gsl_spline_init(s, x, y, (size_t) n);
12233 for (int i = 0; i < n2; i++)
12234 if (x2[i] <= x[0])
12235 y2[i] = y[0];
12236 else if (x2[i] >= x[n - 1])
12237 y2[i] = y[n - 1];
12238 else
12239 y2[i] = gsl_spline_eval(s, x2[i], acc);
12240
12241 /* Free... */
12242 gsl_spline_free(s);
12243 gsl_interp_accel_free(acc);
12244 }
12245
12246 /* Linear interpolation... */
12247 else {
12248 for (int i = 0; i < n2; i++)
12249 if (x2[i] <= x[0])
12250 y2[i] = y[0];
12251 else if (x2[i] >= x[n - 1])
12252 y2[i] = y[n - 1];
12253 else {
12254 const int idx = locate_irr(x, n, x2[i]);
12255 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
12256 }
12257 }
12258}
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 12262 of file mptrac.c.

12264 {
12265
12266 if (n <= 0)
12267 return 0;
12268
12269 float mean = 0, var = 0;
12270
12271 for (int i = 0; i < n; ++i) {
12272 mean += data[i];
12273 var += SQR(data[i]);
12274 }
12275
12276 var = var / (float) n - SQR(mean / (float) n);
12277
12278 return (var > 0 ? sqrtf(var) : 0);
12279}

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

12291 {
12292
12293 struct tm t0, t1;
12294
12295 t0.tm_year = 100;
12296 t0.tm_mon = 0;
12297 t0.tm_mday = 1;
12298 t0.tm_hour = 0;
12299 t0.tm_min = 0;
12300 t0.tm_sec = 0;
12301
12302 t1.tm_year = year - 1900;
12303 t1.tm_mon = mon - 1;
12304 t1.tm_mday = day;
12305 t1.tm_hour = hour;
12306 t1.tm_min = min;
12307 t1.tm_sec = sec;
12308
12309 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
12310}

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

12317 {
12318
12319 static char names[NTIMER][100], groups[NTIMER][100];
12320
12321 static double rt_name[NTIMER], rt_group[NTIMER],
12322 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
12323
12324 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
12325
12326 /* Get time... */
12327 t1 = omp_get_wtime();
12328 dt = t1 - t0;
12329
12330 /* Add elapsed time to current timers... */
12331 if (iname >= 0) {
12332 rt_name[iname] += dt;
12333 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
12334 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
12335 ct_name[iname]++;
12336 }
12337 if (igroup >= 0)
12338 rt_group[igroup] += t1 - t0;
12339
12340 /* Report timers... */
12341 if (output) {
12342 for (int i = 0; i < nname; i++)
12343 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
12344 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
12345 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
12346 for (int i = 0; i < ngroup; i++)
12347 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
12348 double total = 0.0;
12349 for (int i = 0; i < nname; i++)
12350 total += rt_name[i];
12351 LOG(1, "TIMER_TOTAL = %.3f s", total);
12352 }
12353
12354 /* Identify IDs of next timer... */
12355 for (iname = 0; iname < nname; iname++)
12356 if (strcasecmp(name, names[iname]) == 0)
12357 break;
12358 for (igroup = 0; igroup < ngroup; igroup++)
12359 if (strcasecmp(group, groups[igroup]) == 0)
12360 break;
12361
12362 /* Check whether this is a new timer... */
12363 if (iname >= nname) {
12364 sprintf(names[iname], "%s", name);
12365 if ((++nname) >= NTIMER)
12366 ERRMSG("Too many timers!");
12367 }
12368
12369 /* Check whether this is a new group... */
12370 if (igroup >= ngroup) {
12371 sprintf(groups[igroup], "%s", group);
12372 if ((++ngroup) >= NTIMER)
12373 ERRMSG("Too many groups!");
12374 }
12375
12376 /* Save starting time... */
12377 t0 = t1;
12378}
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2240

◆ time_from_filename()

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

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.
with_secondsAn integer indicating if the filename contains seconds or not.
Returns
The time in Julian seconds as a double.

The function performs the following steps:

  • Extracts the year, month, day, hour, minute and (optionally) second 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 formats of the timestamp in the filename are:
  • if with_seconds=0: YYYY-MM-DD_HH-MM (e.g., "2023-05-27_14-45")
  • if with_seconds=1: YYYY-MM-DD_HH-MM-SS (e.g., "2023-05-27_14-45-12")
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 12382 of file mptrac.c.

12385 {
12386
12387 char tstr[10];
12388
12389 double t;
12390
12391 /* Get time from filename... */
12392 int len = (int) strlen(filename);
12393 sprintf(tstr, "%.4s", &filename[len - offset]);
12394 int year = atoi(tstr);
12395 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
12396 int mon = atoi(tstr);
12397 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
12398 int day = atoi(tstr);
12399 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
12400 int hour = atoi(tstr);
12401 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
12402 int min = atoi(tstr);
12403
12404 int sec = 0;
12405 if (with_seconds) {
12406 sprintf(tstr, "%.2s", &filename[len - offset + 17]);
12407 sec = atoi(tstr);
12408 }
12409
12410 /* Check time... */
12411 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
12412 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
12413 ERRMSG("Cannot read time from filename!");
12414
12415 /* Convert time to Julian seconds... */
12416 time2jsec(year, mon, day, hour, min, sec, 0.0, &t);
12417
12418 /* Return time... */
12419 return t;
12420}
Here is the call graph for this function:

◆ tropo_weight()

double tropo_weight ( const ctl_t ctl,
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]ctlPointer to the control data structure.
[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 12424 of file mptrac.c.

12428 {
12429
12430 /* Get tropopause pressure... */
12431 const double pt = clim_tropo(clim, atm->time[ip],
12432 ctl->met_coord_type ==
12433 0 ? atm->lat[ip] : ctl->met_utm_ref_lat);
12434
12435 /* Get pressure range... */
12436 const double p1 = pt * 0.866877899;
12437 const double p0 = pt / 0.866877899;
12438
12439 /* Get weighting factor... */
12440 if (atm->p[ip] > p0)
12441 return 1;
12442 else if (atm->p[ip] < p1)
12443 return 0;
12444 else
12445 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
12446}
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 12450 of file mptrac.c.

12454 {
12455
12456 FILE *out;
12457
12458 /* Set time interval for output... */
12459 const double t0 = t - 0.5 * ctl->dt_mod;
12460 const double t1 = t + 0.5 * ctl->dt_mod;
12461
12462 /* Check if gnuplot output is requested... */
12463 if (ctl->atm_gpfile[0] != '-') {
12464
12465 /* Create gnuplot pipe... */
12466 if (!(out = popen("gnuplot", "w")))
12467 ERRMSG("Cannot create pipe to gnuplot!");
12468
12469 /* Set plot filename... */
12470 fprintf(out, "set out \"%s.png\"\n", filename);
12471
12472 /* Set time string... */
12473 double r;
12474 int year, mon, day, hour, min, sec;
12475 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12476 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12477 year, mon, day, hour, min);
12478
12479 /* Dump gnuplot file to pipe... */
12480 FILE *in;
12481 if (!(in = fopen(ctl->atm_gpfile, "r")))
12482 ERRMSG("Cannot open file!");
12483 char line[LEN];
12484 while (fgets(line, LEN, in))
12485 fprintf(out, "%s", line);
12486 fclose(in);
12487 }
12488
12489 else {
12490
12491 /* Create file... */
12492 if (!(out = fopen(filename, "w")))
12493 ERRMSG("Cannot create file!");
12494 }
12495
12496 /* Write header... */
12497
12498 if (ctl->met_coord_type == 0) {
12499 fprintf(out,
12500 "# $1 = time [s]\n"
12501 "# $2 = altitude [km]\n"
12502 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12503 } else {
12504 fprintf(out,
12505 "# $1 = time [s]\n"
12506 "# $2 = altitude [km]\n" "# $3 = x [m]\n" "# $4 = y [m]\n");
12507 }
12508
12509 for (int iq = 0; iq < ctl->nq; iq++)
12510 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
12511 ctl->qnt_unit[iq]);
12512 fprintf(out, "\n");
12513
12514 /* Write data... */
12515 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
12516
12517 /* Check time... */
12518 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12519 continue;
12520
12521 /* Write output... */
12522 if (ctl->met_coord_type == 0) {
12523 fprintf(out, "%.2f %g %g %g",
12524 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]
12525 );
12526 } else {
12527 fprintf(out, "%.2f %g %.2f %.2f",
12528 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]
12529 );
12530 }
12531
12532 for (int iq = 0; iq < ctl->nq; iq++) {
12533 fprintf(out, " ");
12534 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12535 fprintf(out, ctl->qnt_format[iq], NAN);
12536 else
12537 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
12538 }
12539 fprintf(out, "\n");
12540 }
12541
12542 /* Close file... */
12543 fclose(out);
12544}
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 12548 of file mptrac.c.

12551 {
12552
12553 FILE *out;
12554
12555 /* Create file... */
12556 if (!(out = fopen(filename, "w")))
12557 ERRMSG("Cannot create file!");
12558
12559 /* Write version of binary data... */
12560 int version = 100;
12561 FWRITE(&version, int,
12562 1,
12563 out);
12564
12565 /* Write data... */
12566 FWRITE(&atm->np, int,
12567 1,
12568 out);
12569 FWRITE(atm->time, double,
12570 (size_t) atm->np,
12571 out);
12572 FWRITE(atm->p, double,
12573 (size_t) atm->np,
12574 out);
12575 FWRITE(atm->lon, double,
12576 (size_t) atm->np,
12577 out);
12578 FWRITE(atm->lat, double,
12579 (size_t) atm->np,
12580 out);
12581 for (int iq = 0; iq < ctl->nq; iq++)
12582 FWRITE(atm->q[iq], double,
12583 (size_t) atm->np,
12584 out);
12585
12586 /* Write final flag... */
12587 int final = 999;
12588 FWRITE(&final, int,
12589 1,
12590 out);
12591
12592 /* Close file... */
12593 fclose(out);
12594}

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

12601 {
12602
12603 if (ctl->met_coord_type != 0)
12604 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
12605
12606 int tid, pid, ncid, varid;
12607 size_t start[2], count[2];
12608
12609 /* Create file... */
12610 NC(nc_create(filename, NC_NETCDF4, &ncid));
12611
12612 /* Define dimensions... */
12613 NC(nc_def_dim(ncid, "time", 1, &tid));
12614 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12615
12616 /* Define variables and their attributes... */
12617 int dim_ids[2] = { tid, pid };
12618 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12619 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12620 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
12621 ctl->atm_nc_level, 0);
12622 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
12623 ctl->atm_nc_level, 0);
12624 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
12625 ctl->atm_nc_level, 0);
12626 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
12627 for (int iq = 0; iq < ctl->nq; iq++)
12628 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12629 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12630 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12631
12632 /* Define global attributes... */
12633 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12634 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12635
12636 /* End definitions... */
12637 NC(nc_enddef(ncid));
12638
12639 /* Write data... */
12640 NC_PUT_DOUBLE("time", atm->time, 0);
12641 NC_PUT_DOUBLE("LAT", atm->lat, 0);
12642 NC_PUT_DOUBLE("LON", atm->lon, 0);
12643 NC_PUT_DOUBLE("PRESS", atm->p, 0);
12644 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
12645 for (int iq = 0; iq < ctl->nq; iq++)
12646 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12647
12648 /* Close file... */
12649 NC(nc_close(ncid));
12650}
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1497
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1327
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1411

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

12658 {
12659
12660 if (ctl->met_coord_type != 0)
12661 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
12662
12663 /* Global Counter... */
12664 static size_t out_cnt = 0;
12665
12666 double r, r_start, r_stop;
12667 int year, mon, day, hour, min, sec;
12668 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
12669 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
12670 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
12671
12672 int ncid, varid, tid, pid, cid;
12673 int dim_ids[2];
12674
12675 /* time, nparc */
12676 size_t start[2];
12677 size_t count[2];
12678
12679 /* Determine start and stop times of calculation... */
12680 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12681 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
12682 &min_start, &sec_start, &r_start);
12683 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
12684 &min_stop, &sec_stop, &r_stop);
12685
12686 sprintf(filename_out,
12687 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
12688 year_start % 100, mon_start, day_start, hour_start,
12689 year_stop % 100, mon_stop, day_stop, hour_stop);
12690 LOG(1, "Write traj file: %s", filename_out);
12691
12692 /* Define hyperslap for the traj_file... */
12693 start[0] = out_cnt;
12694 start[1] = 0;
12695 count[0] = 1;
12696 count[1] = (size_t) atm->np;
12697
12698 /* Create the file at the first timestep... */
12699 if (out_cnt == 0) {
12700
12701 /* Create file... */
12702 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
12703
12704 /* Define dimensions... */
12705 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
12706 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12707 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
12708 dim_ids[0] = tid;
12709 dim_ids[1] = pid;
12710
12711 /* Define variables and their attributes... */
12712 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12713 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12714 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
12715 ctl->atm_nc_level, 0);
12716 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
12717 ctl->atm_nc_level, 0);
12718 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
12719 ctl->atm_nc_level, 0);
12720 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
12721 ctl->atm_nc_level, 0);
12722 for (int iq = 0; iq < ctl->nq; iq++)
12723 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12724 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12725 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12726
12727 /* Define global attributes... */
12728 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12729 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12730
12731 /* End definitions... */
12732 NC(nc_enddef(ncid));
12733 NC(nc_close(ncid));
12734 }
12735
12736 /* Increment global counter to change hyperslap... */
12737 out_cnt++;
12738
12739 /* Open file... */
12740 NC(nc_open(filename_out, NC_WRITE, &ncid));
12741
12742 /* Write data... */
12743 NC_PUT_DOUBLE("time", atm->time, 1);
12744 NC_PUT_DOUBLE("LAT", atm->lat, 1);
12745 NC_PUT_DOUBLE("LON", atm->lon, 1);
12746 NC_PUT_DOUBLE("PRESS", atm->p, 1);
12747 if (ctl->advect_vert_coord == 1) {
12748 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
12749 } else if (ctl->qnt_zeta >= 0) {
12750 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
12751 }
12752 for (int iq = 0; iq < ctl->nq; iq++)
12753 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
12754
12755 /* Close file... */
12756 NC(nc_close(ncid));
12757
12758 /* At the last time step create the init_fix_YYYYMMDDHH file... */
12759 if ((year == year_stop) && (mon == mon_stop)
12760 && (day == day_stop) && (hour == hour_stop)) {
12761
12762 /* Set filename... */
12763 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
12764 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
12765 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
12766 LOG(1, "Write init file: %s", filename_init);
12767
12768 /* Create file... */
12769 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
12770
12771 /* Define dimensions... */
12772 NC(nc_def_dim(ncid, "time", 1, &tid));
12773 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12774 dim_ids[0] = tid;
12775 dim_ids[1] = pid;
12776
12777 /* Define variables and their attributes... */
12778 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12779 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12780 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
12781 ctl->atm_nc_level, 0);
12782 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
12783 ctl->atm_nc_level, 0);
12784 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
12785 ctl->atm_nc_level, 0);
12786 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
12787 for (int iq = 0; iq < ctl->nq; iq++)
12788 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12789 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12790 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12791
12792 /* Define global attributes... */
12793 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12794 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12795
12796 /* End definitions... */
12797 NC(nc_enddef(ncid));
12798
12799 /* Write data... */
12800 NC_PUT_DOUBLE("time", atm->time, 0);
12801 NC_PUT_DOUBLE("LAT", atm->lat, 0);
12802 NC_PUT_DOUBLE("LON", atm->lon, 0);
12803 NC_PUT_DOUBLE("PRESS", atm->p, 0);
12804 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
12805 for (int iq = 0; iq < ctl->nq; iq++)
12806 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12807
12808 /* Close file... */
12809 NC(nc_close(ncid));
12810 }
12811}
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 12815 of file mptrac.c.

12818 {
12819
12820 int ncid, obsid, varid;
12821
12822 size_t start[2], count[2];
12823
12824 /* Create file... */
12825 NC(nc_create(filename, NC_NETCDF4, &ncid));
12826
12827 /* Define dimensions... */
12828 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
12829
12830 /* Define variables and their attributes... */
12831 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
12832 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12833 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
12834 ctl->atm_nc_level, 0);
12835 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
12836 ctl->atm_nc_level, 0);
12837 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
12838 ctl->atm_nc_level, 0);
12839 for (int iq = 0; iq < ctl->nq; iq++)
12840 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
12841 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
12842 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12843
12844 /* Define global attributes... */
12845 NC_PUT_ATT_GLOBAL("featureType", "point");
12846
12847 /* End definitions... */
12848 NC(nc_enddef(ncid));
12849
12850 /* Write data... */
12851 NC_PUT_DOUBLE("time", atm->time, 0);
12852 NC_PUT_DOUBLE("press", atm->p, 0);
12853 NC_PUT_DOUBLE("lon", atm->lon, 0);
12854 NC_PUT_DOUBLE("lat", atm->lat, 0);
12855 for (int iq = 0; iq < ctl->nq; iq++)
12856 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12857
12858 /* Close file... */
12859 NC(nc_close(ncid));
12860}

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

12868 {
12869
12870 if (ctl->met_coord_type != 0)
12871 ERRMSG("Only lat/lon grid supported");
12872
12873 static FILE *out;
12874
12875 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
12876 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
12877
12878 static int *obscount, nobs, nk;
12879
12880 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
12881
12882 const int ensemble = (ctl->nens > 0);
12883
12884 /* Set timer */
12885 SELECT_TIMER("WRITE_CSI", "OUTPUT");
12886
12887 /* Check quantities... */
12888 if (ctl->qnt_m < 0)
12889 ERRMSG("Need quantity mass!");
12890 if (ensemble) {
12891 if (ctl->qnt_ens < 0)
12892 ERRMSG("Missing ensemble IDs!");
12893 if (ctl->nens > NENS)
12894 ERRMSG("Too many ensembles!");
12895 }
12896
12897 /* Init... */
12898 if (t == ctl->t_start) {
12899
12900 /* Allocate.. */
12901 ALLOC(area, double,
12902 ctl->csi_ny);
12903 ALLOC(rt, double,
12904 NOBS);
12905 ALLOC(rz, double,
12906 NOBS);
12907 ALLOC(rlon, double,
12908 NOBS);
12909 ALLOC(rlat, double,
12910 NOBS);
12911 ALLOC(robs, double,
12912 NOBS);
12913
12914 /* Read observation data... */
12915 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12916
12917 /* Read kernel data... */
12918 if (ctl->csi_kernel[0] != '-')
12919 read_kernel(ctl->csi_kernel, kz, kw, &nk);
12920
12921 /* Create new file... */
12922 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
12923 if (!(out = fopen(filename, "w")))
12924 ERRMSG("Cannot create file!");
12925
12926 /* Write header... */
12927 fprintf(out,
12928 "# $1 = time [s]\n"
12929 "# $2 = ensemble ID\n"
12930 "# $3 = number of hits (cx)\n"
12931 "# $4 = number of misses (cy)\n"
12932 "# $5 = number of false alarms (cz)\n"
12933 "# $6 = number of observations (cx + cy)\n"
12934 "# $7 = number of forecasts (cx + cz)\n"
12935 "# $8 = bias (%%)\n"
12936 "# $9 = POD (%%)\n"
12937 "# $10 = FAR (%%)\n"
12938 "# $11 = CSI (%%)\n"
12939 "# $12 = hits by random chance\n"
12940 "# $13 = ETS (%%)\n"
12941 "# $14 = Pearson R\n"
12942 "# $15 = Spearman R\n"
12943 "# $16 = mean error [kg/m²]\n"
12944 "# $17 = RMSE [kg/m²]\n"
12945 "# $18 = MAE [kg/m²]\n"
12946 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
12947
12948 /* Set grid box size... */
12949 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
12950 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
12951 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
12952
12953 /* Set horizontal coordinates... */
12954 for (int iy = 0; iy < ctl->csi_ny; iy++) {
12955 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
12956 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
12957 }
12958 }
12959
12960 /* Set time interval... */
12961 const double t0 = t - 0.5 * ctl->dt_mod;
12962 const double t1 = t + 0.5 * ctl->dt_mod;
12963
12964 /* Allocate... */
12965 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
12966 ALLOC(modmean, double,
12967 (ensemble ? ctl->nens : 1) * grid_size);
12968 ALLOC(obsmean, double,
12969 grid_size);
12970 ALLOC(obscount, int,
12971 grid_size);
12972 ALLOC(obsstd, double,
12973 grid_size);
12974
12975 /* Init... */
12976 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
12977 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
12978
12979 /* Loop over observations... */
12980 for (int i = 0; i < nobs; i++) {
12981 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
12982 continue;
12983
12984 /* Calculate indices... */
12985 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
12986 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
12987 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
12988 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
12989 || iz >= ctl->csi_nz)
12990 continue;
12991
12992 /* Get mean observation index... */
12993 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
12994 obsmean[idx] += robs[i];
12995 obsstd[idx] += SQR(robs[i]);
12996 obscount[idx]++;
12997 }
12998
12999 /* Analyze model data... */
13000 for (int ip = 0; ip < atm->np; ip++) {
13001
13002 /* Check time... */
13003 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13004 continue;
13005
13006 /* Get ensemble ID... */
13007 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
13008 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
13009 ERRMSG("Ensemble ID out of range!");
13010
13011 /* Get indices... */
13012 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
13013 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
13014 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
13015 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
13016 || iz >= ctl->csi_nz)
13017 continue;
13018
13019 /* Get total mass in grid cell... */
13020 const int idx =
13021 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13022 modmean[idx] +=
13023 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13024 }
13025 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
13026 /* Analyze all grid cells... */
13027 for (int ix = 0; ix < ctl->csi_nx; ix++)
13028 for (int iy = 0; iy < ctl->csi_ny; iy++)
13029 for (int iz = 0; iz < ctl->csi_nz; iz++) {
13030
13031 /* Calculate mean observation index... */
13032 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13033 if (e == 0)
13034 if (obscount[idx]) {
13035 obsmean[idx] /= obscount[idx];
13036 obsstd[idx] =
13037 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
13038 }
13039
13040 /* Calculate model mean per ensemble... */
13041 const int midx = e * grid_size + idx;
13042 if (modmean[midx] > 0)
13043 modmean[midx] /= (1e6 * area[iy]);
13044
13045 /* Check number of observations... */
13046 if (obscount[idx]) {
13047
13048 /* Calculate CSI... */
13049 ct[e]++;
13050 if (obsmean[idx] >= ctl->csi_obsmin
13051 && modmean[midx] >= ctl->csi_modmin)
13052 cx[e]++;
13053 else if (obsmean[idx] >= ctl->csi_obsmin)
13054 cy[e]++;
13055 else if (modmean[midx] >= ctl->csi_modmin)
13056 cz[e]++;
13057
13058 /* Save data for other verification statistics... */
13059 if (obsmean[idx] >= ctl->csi_obsmin
13060 || modmean[midx] >= ctl->csi_modmin) {
13061 x[n[e]] = modmean[midx];
13062 y[n[e]] = obsmean[idx];
13063 if (modmean[midx] >= ctl->csi_modmin)
13064 obsstdn[n[e]] = obsstd[idx];
13065 if ((++n[e]) >= NCSI)
13066 ERRMSG("Too many points for statistics!");
13067 }
13068 }
13069 }
13070 /* Write output... */
13071 if (fmod(t, ctl->csi_dt_out) == 0) {
13072
13073 if (n[e] == 0)
13074 continue;
13075
13076 /* Calculate verification statistics
13077 (https://www.cawcr.gov.au/projects/verification/) ... */
13078 static double work[2 * NCSI], work2[2 * NCSI];
13079 const int n_obs = cx[e] + cy[e];
13080 const int n_for = cx[e] + cz[e];
13081 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
13082 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
13083 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
13084 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
13085 const double csi =
13086 (cx[e] + cy[e] + cz[e] >
13087 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
13088 const double ets =
13089 (cx[e] + cy[e] + cz[e] - cx_rd >
13090 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
13091 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
13092 const double rho_s =
13093 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
13094 for (int i = 0; i < n[e]; i++) {
13095 work[i] = x[i] - y[i];
13096 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
13097 }
13098 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
13099 const double rmse =
13100 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
13101 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
13102 const double loglikelihood =
13103 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
13104
13105 /* Write... */
13106 fprintf(out,
13107 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
13108 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
13109 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
13110 loglikelihood, n[e]);
13111
13112 /* Set counters to zero... */
13113 for (int i = 0; i < n[e]; i++)
13114 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
13115 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
13116 }
13117 }
13118 /* Free... */
13119 free(modmean);
13120 free(obsmean);
13121 free(obscount);
13122 free(obsstd);
13123
13124 /* Finalize... */
13125 if (t == ctl->t_stop) {
13126
13127 /* Close output file... */
13128 fclose(out);
13129
13130 /* Free... */
13131 free(area);
13132 free(rt);
13133 free(rz);
13134 free(rlon);
13135 free(rlat);
13136 free(robs);
13137 }
13138}
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:12009
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:8522
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:3298
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:374
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:369
Here is the call graph for this function:

◆ write_ens()

void write_ens ( const char *  filename,
const ctl_t ctl,
const atm_t atm,
const double  t 
)

Writes ensemble data to a file.

The write_ens function processes air parcel data to calculate ensemble means and standard deviations for various quantities and writes them to a specified output file. It handles ensemble members and calculates statistics such as means and standard deviations for each ensemble, along with latitude, longitude, altitude, and time information.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.
tA double representing the current time.

The function performs the following steps:

  • Initializes resources and sets up necessary variables.
  • Sets a time interval for processing data.
  • Loops over air parcels to accumulate means and standard deviations for each ensemble member.
  • Creates an output file and writes header information.
  • Writes ensemble data, including time, altitude, latitude, longitude, means, standard deviations, and the number of members.
  • Closes the output file.
Author
Lars Hoffmann

Definition at line 13142 of file mptrac.c.

13146 {
13147
13148 if (ctl->met_coord_type != 0)
13149 ERRMSG("Only lat/lon grid supported");
13150
13151 static FILE *out;
13152
13153 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
13154 x[3], zm[NENS];
13155
13156 static int n[NENS];
13157
13158 /* Set timer... */
13159 SELECT_TIMER("WRITE_ENS", "OUTPUT");
13160
13161 /* Check quantities... */
13162 if (ctl->qnt_ens < 0)
13163 ERRMSG("Missing ensemble IDs!");
13164
13165 /* Set time interval... */
13166 const double t0 = t - 0.5 * ctl->dt_mod;
13167 const double t1 = t + 0.5 * ctl->dt_mod;
13168
13169 /* Init... */
13170 for (int i = 0; i < NENS; i++) {
13171 for (int iq = 0; iq < ctl->nq; iq++)
13172 qm[iq][i] = qs[iq][i] = 0;
13173 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
13174 n[i] = 0;
13175 }
13176
13177 /* Loop over air parcels... */
13178 for (int ip = 0; ip < atm->np; ip++) {
13179
13180 /* Check time... */
13181 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13182 continue;
13183
13184 /* Check ensemble ID... */
13185 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
13186 ERRMSG("Ensemble ID is out of range!");
13187
13188 /* Get means... */
13189 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
13190 for (int iq = 0; iq < ctl->nq; iq++) {
13191 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
13192 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
13193 }
13194 xm[ctl->qnt_ens][0] += x[0];
13195 xm[ctl->qnt_ens][1] += x[1];
13196 xm[ctl->qnt_ens][2] += x[2];
13197 zm[ctl->qnt_ens] += Z(atm->p[ip]);
13198 n[ctl->qnt_ens]++;
13199 }
13200
13201 /* Create file... */
13202 LOG(1, "Write ensemble data: %s", filename);
13203 if (!(out = fopen(filename, "w")))
13204 ERRMSG("Cannot create file!");
13205
13206 /* Write header... */
13207 fprintf(out,
13208 "# $1 = time [s]\n"
13209 "# $2 = altitude [km]\n"
13210 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13211 for (int iq = 0; iq < ctl->nq; iq++)
13212 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
13213 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13214 for (int iq = 0; iq < ctl->nq; iq++)
13215 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
13216 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13217 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
13218
13219 /* Write data... */
13220 for (int i = 0; i < NENS; i++)
13221 if (n[i] > 0) {
13222 cart2geo(xm[i], &dummy, &lon, &lat);
13223 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
13224 for (int iq = 0; iq < ctl->nq; iq++) {
13225 fprintf(out, " ");
13226 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
13227 }
13228 for (int iq = 0; iq < ctl->nq; iq++) {
13229 fprintf(out, " ");
13230 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
13231 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
13232 }
13233 fprintf(out, " %d\n", n[i]);
13234 }
13235
13236 /* Close file... */
13237 fclose(out);
13238}
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
Here is the call graph for this function:

◆ write_grid()

void write_grid ( const char *  filename,
const ctl_t ctl,
met_t met0,
met_t met1,
const atm_t atm,
const double  t 
)

Writes grid data to a file in ASCII or netCDF format.

The write_grid function processes air parcel data to calculate various grid-based statistics such as column density, mean, and standard deviation for specified quantities. It then writes this data to a specified output file either in ASCII or netCDF format based on the configuration parameters provided in the ctl structure.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
met0A pointer to a met_t structure containing meteorological data for the initial time step.
met1A pointer to a met_t structure containing meteorological data for the final time step.
atmA pointer to an atm_t structure containing atmospheric data.
tA double representing the current time.

The function performs the following steps:

  • Initializes resources and sets up necessary variables.
  • Reads kernel data if it is specified in the control parameters.
  • Allocates memory for various arrays to store grid data.
  • Determines the grid box size and sets up vertical and horizontal coordinates.
  • Sets a time interval for output data processing.
  • Calculates grid box indices for atmospheric model data.
  • Averages data within each grid box.
  • Calculates column density and volume mixing ratio.
  • Writes data to the output file either in ASCII or netCDF format based on the specified grid_type in the control parameters.
  • Frees allocated memory.
Note
The function supports parallel processing using OpenMP for certain computational tasks to improve performance.
Author
Lars Hoffmann

Definition at line 13242 of file mptrac.c.

13248 {
13249
13250 if (ctl->met_coord_type != 0)
13251 ERRMSG("Only lat/lon grid supported");
13252
13253 static double kz[EP], kw[EP];
13254
13255 static int nk;
13256
13257 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
13258
13259 int *ixs, *iys, *izs, *np;
13260
13261 /* Set timer... */
13262 SELECT_TIMER("WRITE_GRID", "OUTPUT");
13263
13264 /* Write info... */
13265 LOG(1, "Write grid data: %s", filename);
13266
13267 /* Init... */
13268 if (t == ctl->t_start) {
13269
13270 /* Read kernel data... */
13271 if (ctl->grid_kernel[0] != '-')
13272 read_kernel(ctl->grid_kernel, kz, kw, &nk);
13273 }
13274
13275 /* Allocate... */
13276 ALLOC(cd, double,
13277 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13278 for (int iq = 0; iq < ctl->nq; iq++) {
13279 ALLOC(mean[iq], double,
13280 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13281 ALLOC(sigma[iq], double,
13282 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13283 }
13284 ALLOC(vmr_impl, double,
13285 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13286 ALLOC(z, double,
13287 ctl->grid_nz);
13288 ALLOC(lon, double,
13289 ctl->grid_nx);
13290 ALLOC(lat, double,
13291 ctl->grid_ny);
13292 ALLOC(area, double,
13293 ctl->grid_ny);
13294 ALLOC(press, double,
13295 ctl->grid_nz);
13296 ALLOC(np, int,
13297 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13298 ALLOC(ixs, int,
13299 atm->np);
13300 ALLOC(iys, int,
13301 atm->np);
13302 ALLOC(izs, int,
13303 atm->np);
13304
13305 /* Set grid box size... */
13306 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
13307 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
13308 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
13309
13310 /* Set vertical coordinates... */
13311#pragma omp parallel for default(shared)
13312 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13313 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
13314 press[iz] = P(z[iz]);
13315 }
13316
13317 /* Set horizontal coordinates... */
13318 for (int ix = 0; ix < ctl->grid_nx; ix++)
13319 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
13320#pragma omp parallel for default(shared)
13321 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13322 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
13323 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13324 }
13325
13326 /* Set time interval for output... */
13327 const double t0 = t - 0.5 * ctl->dt_mod;
13328 const double t1 = t + 0.5 * ctl->dt_mod;
13329
13330 /* Get grid box indices... */
13331#pragma omp parallel for default(shared)
13332 for (int ip = 0; ip < atm->np; ip++) {
13333 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
13334 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
13335 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
13336 if (atm->time[ip] < t0 || atm->time[ip] > t1
13337 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
13338 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
13339 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
13340 izs[ip] = -1;
13341 }
13342
13343 /* Average data... */
13344 for (int ip = 0; ip < atm->np; ip++)
13345 if (izs[ip] >= 0) {
13346 const int idx =
13347 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
13348 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
13349 np[idx]++;
13350 for (int iq = 0; iq < ctl->nq; iq++) {
13351 mean[iq][idx] += kernel * atm->q[iq][ip];
13352 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
13353 }
13354 }
13355
13356 /* Calculate column density and volume mixing ratio... */
13357#pragma omp parallel for default(shared)
13358 for (int ix = 0; ix < ctl->grid_nx; ix++)
13359 for (int iy = 0; iy < ctl->grid_ny; iy++)
13360 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13361
13362 /* Get grid index... */
13363 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
13364
13365 /* Calculate column density... */
13366 cd[idx] = NAN;
13367 if (ctl->qnt_m >= 0)
13368 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
13369
13370 /* Calculate volume mixing ratio (implicit)... */
13371 vmr_impl[idx] = NAN;
13372 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
13373 && met1 != NULL) {
13374 vmr_impl[idx] = 0;
13375 if (mean[ctl->qnt_m][idx] > 0) {
13376
13377 /* Get temperature... */
13378 double temp;
13380 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
13381 lon[ix], lat[iy], &temp, ci, cw, 1);
13382
13383 /* Calculate volume mixing ratio... */
13384 vmr_impl[idx] =
13385 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
13386 }
13387 }
13388
13389 /* Calculate mean... */
13390 if (np[idx] > 0)
13391 for (int iq = 0; iq < ctl->nq; iq++) {
13392 mean[iq][idx] /= np[idx];
13393 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
13394 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
13395 } else
13396 for (int iq = 0; iq < ctl->nq; iq++) {
13397 mean[iq][idx] = NAN;
13398 sigma[iq][idx] = NAN;
13399 }
13400 }
13401
13402 /* Write ASCII data... */
13403 if (ctl->grid_type == 0)
13404 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
13405 t, z, lon, lat, area, dz, np);
13406
13407 /* Write netCDF data... */
13408 else if (ctl->grid_type == 1)
13409 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
13410 t, z, lon, lat, area, dz, np);
13411
13412 /* Error message... */
13413 else
13414 ERRMSG("Grid data format GRID_TYPE unknown!");
13415
13416 /* Free... */
13417 free(cd);
13418 for (int iq = 0; iq < ctl->nq; iq++) {
13419 free(mean[iq]);
13420 free(sigma[iq]);
13421 }
13422 free(vmr_impl);
13423 free(z);
13424 free(lon);
13425 free(lat);
13426 free(area);
13427 free(press);
13428 free(np);
13429 free(ixs);
13430 free(iys);
13431 free(izs);
13432}
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:13436
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:13540
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 13436 of file mptrac.c.

13449 {
13450
13451 FILE *out;
13452
13453 /* Check if gnuplot output is requested... */
13454 if (ctl->grid_gpfile[0] != '-') {
13455
13456 /* Create gnuplot pipe... */
13457 if (!(out = popen("gnuplot", "w")))
13458 ERRMSG("Cannot create pipe to gnuplot!");
13459
13460 /* Set plot filename... */
13461 fprintf(out, "set out \"%s.png\"\n", filename);
13462
13463 /* Set time string... */
13464 double r;
13465 int year, mon, day, hour, min, sec;
13466 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
13467 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
13468 year, mon, day, hour, min);
13469
13470 /* Dump gnuplot file to pipe... */
13471 FILE *in;
13472 char line[LEN];
13473 if (!(in = fopen(ctl->grid_gpfile, "r")))
13474 ERRMSG("Cannot open file!");
13475 while (fgets(line, LEN, in))
13476 fprintf(out, "%s", line);
13477 fclose(in);
13478 }
13479
13480 else {
13481
13482 /* Create file... */
13483 if (!(out = fopen(filename, "w")))
13484 ERRMSG("Cannot create file!");
13485 }
13486
13487 /* Write header... */
13488 fprintf(out,
13489 "# $1 = time [s]\n"
13490 "# $2 = altitude [km]\n"
13491 "# $3 = longitude [deg]\n"
13492 "# $4 = latitude [deg]\n"
13493 "# $5 = surface area [km^2]\n"
13494 "# $6 = layer depth [km]\n"
13495 "# $7 = column density (implicit) [kg/m^2]\n"
13496 "# $8 = volume mixing ratio (implicit) [ppv]\n"
13497 "# $9 = number of particles [1]\n");
13498 for (int iq = 0; iq < ctl->nq; iq++)
13499 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
13500 ctl->qnt_unit[iq]);
13501 if (ctl->grid_stddev)
13502 for (int iq = 0; iq < ctl->nq; iq++)
13503 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
13504 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13505 fprintf(out, "\n");
13506
13507 /* Write data... */
13508 for (int ix = 0; ix < ctl->grid_nx; ix++) {
13509 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
13510 fprintf(out, "\n");
13511 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13512 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
13513 fprintf(out, "\n");
13514 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13515 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
13516 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
13517 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
13518 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
13519 for (int iq = 0; iq < ctl->nq; iq++) {
13520 fprintf(out, " ");
13521 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
13522 }
13523 if (ctl->grid_stddev)
13524 for (int iq = 0; iq < ctl->nq; iq++) {
13525 fprintf(out, " ");
13526 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
13527 }
13528 fprintf(out, "\n");
13529 }
13530 }
13531 }
13532 }
13533
13534 /* Close file... */
13535 fclose(out);
13536}
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 13540 of file mptrac.c.

13553 {
13554
13555 char longname[2 * LEN], varname[2 * LEN];
13556
13557 double *help;
13558
13559 int *help2, ncid, dimid[10], varid;
13560
13561 size_t start[2], count[2];
13562
13563 /* Allocate... */
13564 ALLOC(help, double,
13565 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13566 ALLOC(help2, int,
13567 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13568
13569 /* Create file... */
13570 NC(nc_create(filename, NC_NETCDF4, &ncid));
13571
13572 /* Define dimensions... */
13573 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
13574 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
13575 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
13576 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
13577 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
13578
13579 /* Define variables and their attributes... */
13580 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
13581 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
13582 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
13583 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
13584 0);
13585 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
13586 0);
13587 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
13588 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
13589
13590 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
13591 ctl->grid_nc_level, 0);
13592 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
13593 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
13594 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
13595 for (int iq = 0; iq < ctl->nq; iq++) {
13596 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
13597 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
13598 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
13599 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
13600 if (ctl->grid_stddev) {
13601 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
13602 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
13603 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
13604 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
13605 }
13606 }
13607 /* End definitions... */
13608 NC(nc_enddef(ncid));
13609
13610 /* Write data... */
13611 NC_PUT_DOUBLE("time", &t, 0);
13612 NC_PUT_DOUBLE("lon", lon, 0);
13613 NC_PUT_DOUBLE("lat", lat, 0);
13614 NC_PUT_DOUBLE("z", z, 0);
13615 NC_PUT_DOUBLE("area", area, 0);
13616 NC_PUT_DOUBLE("dz", &dz, 0);
13617
13618 for (int ix = 0; ix < ctl->grid_nx; ix++)
13619 for (int iy = 0; iy < ctl->grid_ny; iy++)
13620 for (int iz = 0; iz < ctl->grid_nz; iz++)
13621 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13622 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13623 NC_PUT_DOUBLE("cd", help, 0);
13624
13625 for (int ix = 0; ix < ctl->grid_nx; ix++)
13626 for (int iy = 0; iy < ctl->grid_ny; iy++)
13627 for (int iz = 0; iz < ctl->grid_nz; iz++)
13628 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13629 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13630 NC_PUT_DOUBLE("vmr_impl", help, 0);
13631
13632 for (int ix = 0; ix < ctl->grid_nx; ix++)
13633 for (int iy = 0; iy < ctl->grid_ny; iy++)
13634 for (int iz = 0; iz < ctl->grid_nz; iz++)
13635 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13636 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13637 NC_PUT_INT("np", help2, 0);
13638
13639 for (int iq = 0; iq < ctl->nq; iq++) {
13640 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
13641 for (int ix = 0; ix < ctl->grid_nx; ix++)
13642 for (int iy = 0; iy < ctl->grid_ny; iy++)
13643 for (int iz = 0; iz < ctl->grid_nz; iz++)
13644 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13645 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13646 NC_PUT_DOUBLE(varname, help, 0);
13647 }
13648
13649 if (ctl->grid_stddev)
13650 for (int iq = 0; iq < ctl->nq; iq++) {
13651 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
13652 for (int ix = 0; ix < ctl->grid_nx; ix++)
13653 for (int iy = 0; iy < ctl->grid_ny; iy++)
13654 for (int iz = 0; iz < ctl->grid_nz; iz++)
13655 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13656 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13657 NC_PUT_DOUBLE(varname, help, 0);
13658 }
13659
13660 /* Close file... */
13661 NC(nc_close(ncid));
13662
13663 /* Free... */
13664 free(help);
13665 free(help2);
13666}
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1458

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

13673 {
13674
13675 /* Create file... */
13676 FILE *out, *level_log = NULL;
13677 if (!(out = fopen(filename, "w")))
13678 ERRMSG("Cannot create file!");
13679
13680 /* Create diagnostics file... */
13681 if (strcmp(ctl->met_comp_logfile, "-") != 0) {
13682
13683 if (!(level_log = fopen(ctl->met_comp_logfile, "w")))
13684 ERRMSG("Cannot create compression log file!");
13685 LOG(1, "Write compression diagnostics: %s", ctl->met_comp_logfile);
13686
13687 /* Write header... */
13688 fprintf(level_log,
13689 "# $1 = compression codec name [-]\n"
13690 "# $2 = variable name [-]\n"
13691 "# $3 = level index [-]\n"
13692 "# $4 = pressure level [hPa]\n"
13693 "# $5 = compression ratio [-]\n"
13694 "# $6 = bits per value [bit/value]\n"
13695 "# $7 = correlation coefficient [-]\n"
13696 "# $8 = mean compression error [-]\n"
13697 "# $9 = standard deviation of compression error [-]\n"
13698 "# $10 = minimum compression error [-]\n"
13699 "# $11 = maximum compression error [-]\n"
13700 "# $12 = mean value of original field [-]\n"
13701 "# $13 = value range of original field [-]\n"
13702 "# $14 = normalized root mean square error [-]\n"
13703 "# $15 = compression time [s]\n"
13704 "# $16 = compression speed [MiB/s]\n"
13705 "# $17 = decompression time [s]\n"
13706 "# $18 = decompression speed [MiB/s]\n\n");
13707 }
13708
13709 /* Write type of binary data... */
13710 FWRITE(&ctl->met_type, int,
13711 1,
13712 out);
13713
13714 /* Write version of binary data... */
13715 int version = 104;
13716 FWRITE(&version, int,
13717 1,
13718 out);
13719
13720 /* Write grid data... */
13721 FWRITE(&met->time, double,
13722 1,
13723 out);
13724 FWRITE(&met->nx, int,
13725 1,
13726 out);
13727 FWRITE(&met->ny, int,
13728 1,
13729 out);
13730 FWRITE(&met->np, int,
13731 1,
13732 out);
13733 FWRITE(met->lon, double,
13734 (size_t) met->nx,
13735 out);
13736 FWRITE(met->lat, double,
13737 (size_t) met->ny,
13738 out);
13739 FWRITE(met->p, double,
13740 (size_t) met->np,
13741 out);
13742
13743 /* Write surface data... */
13744 write_met_bin_2d(out, met, met->ps, "PS");
13745 write_met_bin_2d(out, met, met->ts, "TS");
13746 write_met_bin_2d(out, met, met->zs, "ZS");
13747 write_met_bin_2d(out, met, met->us, "US");
13748 write_met_bin_2d(out, met, met->vs, "VS");
13749 write_met_bin_2d(out, met, met->ess, "ESS");
13750 write_met_bin_2d(out, met, met->nss, "NSS");
13751 write_met_bin_2d(out, met, met->shf, "SHF");
13752 write_met_bin_2d(out, met, met->lsm, "LSM");
13753 write_met_bin_2d(out, met, met->sst, "SST");
13754 write_met_bin_2d(out, met, met->pbl, "PBL");
13755 write_met_bin_2d(out, met, met->pt, "PT");
13756 write_met_bin_2d(out, met, met->tt, "TT");
13757 write_met_bin_2d(out, met, met->zt, "ZT");
13758 write_met_bin_2d(out, met, met->h2ot, "H2OT");
13759 write_met_bin_2d(out, met, met->pct, "PCT");
13760 write_met_bin_2d(out, met, met->pcb, "PCB");
13761 write_met_bin_2d(out, met, met->cl, "CL");
13762 write_met_bin_2d(out, met, met->plcl, "PLCL");
13763 write_met_bin_2d(out, met, met->plfc, "PLFC");
13764 write_met_bin_2d(out, met, met->pel, "PEL");
13765 write_met_bin_2d(out, met, met->cape, "CAPE");
13766 write_met_bin_2d(out, met, met->cin, "CIN");
13767 write_met_bin_2d(out, met, met->o3c, "O3C");
13768
13769 /* Write level data... */
13770 write_met_bin_3d(out, ctl, met, met->z, "Z", 0, level_log);
13771 write_met_bin_3d(out, ctl, met, met->t, "T", 1, level_log);
13772 write_met_bin_3d(out, ctl, met, met->u, "U", 2, level_log);
13773 write_met_bin_3d(out, ctl, met, met->v, "V", 3, level_log);
13774 write_met_bin_3d(out, ctl, met, met->w, "W", 4, level_log);
13775 write_met_bin_3d(out, ctl, met, met->pv, "PV", 5, level_log);
13776 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", 6, level_log);
13777 write_met_bin_3d(out, ctl, met, met->o3, "O3", 7, level_log);
13778 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", 8, level_log);
13779 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", 9, level_log);
13780 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", 10, level_log);
13781 write_met_bin_3d(out, ctl, met, met->swc, "SWC", 11, level_log);
13782 write_met_bin_3d(out, ctl, met, met->cc, "CC", 12, level_log);
13783 if (METVAR != 13)
13784 ERRMSG("Number of meteo variables doesn't match!");
13785
13786 /* Write final flag... */
13787 int final = 999;
13788 FWRITE(&final, int,
13789 1,
13790 out);
13791
13792 /* Close file... */
13793 if (level_log)
13794 fclose(level_log);
13795 fclose(out);
13796}
void write_met_bin_3d(FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int metvar, FILE *level_log)
Writes a 3-dimensional meteorological variable to a binary file.
Definition: mptrac.c:13829
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:13800
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 13800 of file mptrac.c.

13804 {
13805
13806 float *help;
13807
13808 /* Allocate... */
13809 ALLOC(help, float,
13810 EX * EY);
13811
13812 /* Copy data... */
13813 for (int ix = 0; ix < met->nx; ix++)
13814 for (int iy = 0; iy < met->ny; iy++)
13815 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
13816
13817 /* Write uncompressed data... */
13818 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
13819 FWRITE(help, float,
13820 (size_t) (met->nx * met->ny),
13821 out);
13822
13823 /* Free... */
13824 free(help);
13825}

◆ write_met_bin_3d()

void write_met_bin_3d ( FILE *  out,
const ctl_t ctl,
met_t met,
float  var[EX][EY][EP],
const char *  varname,
const int  metvar,
FILE *  level_log 
)

Writes a 3-dimensional meteorological variable to a binary file.

The write_met_bin_3d function writes a 3-dimensional meteorological variable to a binary file specified by the out parameter. The variable data is provided in a 3-dimensional array var with maximum dimensions EX by EY by EP. The variable name is provided as a string in the varname parameter. Additionally, the function takes parameters for specifying the compression precision and tolerance.

Parameters
outA pointer to a FILE structure representing the output file.
ctlA pointer to a ctl_t structure containing control parameters.
metA pointer to a met_t structure containing meteorological data.
varAn array of floats representing the 3-dimensional variable data.
varnameA string containing the name of the variable being written.
metvarIndex of the meteorological variable, used to select codec-specific compression settings.
level_logOptional file stream for per-level compression diagnostics, or NULL to disable logging.

The function performs the following steps:

  • Allocates memory for a temporary buffer to hold the variable data.
  • Copies the variable data from the 3-dimensional array var to the temporary buffer help.
  • Writes the variable data to the binary file specified by out using the specified compression method (uncompressed, packed, ZFP, ZSTD, cmultiscale).
  • Logs a message indicating the successful writing of the variable data.
  • Frees the allocated memory.
Note
This function is typically used to write level data or other 3-dimensional meteorological variables to a binary file.
Depending on the value of ctl->met_type, the function writes the variable data using different compression methods. If ctl->met_type is not supported, an error message is logged.
Author
Lars Hoffmann

Definition at line 13829 of file mptrac.c.

13836 {
13837
13838 float *help;
13839
13840 /* Allocate... */
13841 ALLOC(help, float,
13842 EX * EY * EP);
13843
13844 /* Copy data... */
13845#pragma omp parallel for default(shared) collapse(2)
13846 for (int ix = 0; ix < met->nx; ix++)
13847 for (int iy = 0; iy < met->ny; iy++)
13848 for (int ip = 0; ip < met->np; ip++)
13849 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
13850
13851 /* Write uncompressed data... */
13852 if (ctl->met_type == 1) {
13853 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
13854 FWRITE(help, float,
13855 (size_t) (met->nx * met->ny * met->np),
13856 out);
13857 }
13858
13859 /* Write packed data... */
13860 else if (ctl->met_type == 2)
13861 compress_pck(ctl, met, varname, help, 0, level_log, out);
13862
13863 /* Write ZFP data... */
13864#ifdef ZFP
13865 else if (ctl->met_type == 3) {
13866 FWRITE(&ctl->met_zfp_prec[metvar], int,
13867 1,
13868 out);
13869 FWRITE(&ctl->met_zfp_tol[metvar], double,
13870 1,
13871 out);
13872 compress_zfp(ctl, met, varname, help, 0, level_log, out);
13873 }
13874#endif
13875
13876 /* Write zstd data... */
13877#ifdef ZSTD
13878 else if (ctl->met_type == 4)
13879 compress_zstd(ctl, met, varname, help, 0, level_log, out);
13880#endif
13881
13882 /* Write LZ4 data... */
13883#ifdef LZ4
13884 else if (ctl->met_type == 8)
13885 compress_lz4(ctl, met, varname, help, 0, level_log, out);
13886#endif
13887
13888 /* Write cmultiscale data... */
13889#ifdef CMS
13890 else if (ctl->met_type == 5) {
13891 compress_cms(ctl, met, varname, help, 0, level_log, out);
13892 }
13893#endif
13894
13895 /* Write SZ3 data... */
13896#ifdef SZ3
13897 else if (ctl->met_type == 7) {
13898 FWRITE(&ctl->met_sz3_prec[metvar], int,
13899 1,
13900 out);
13901 FWRITE(&ctl->met_sz3_tol[metvar], double,
13902 1,
13903 out);
13904 compress_sz3(ctl, met, varname, help, 0, level_log, out);
13905 }
13906#endif
13907
13908 /* Unknown method... */
13909 else {
13910 ERRMSG("MET_TYPE not supported!");
13911
13912 /* This will never execute, hack to avoid compilation error... */
13913 LOG(3, "%d", metvar);
13914 }
13915
13916 /* Free... */
13917 free(help);
13918}
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 13922 of file mptrac.c.

13925 {
13926
13927 /* Create file... */
13928 int ncid, varid;
13929 size_t start[4], count[4];
13930 NC(nc_create(filename, NC_NETCDF4, &ncid));
13931
13932 /* Define dimensions... */
13933 int tid, lonid, latid, levid;
13934 NC(nc_def_dim(ncid, "time", 1, &tid));
13935
13936 if (met->coord_type == 0) {
13937 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
13938 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
13939 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0,
13940 0);
13941 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0,
13942 0);
13943 } else {
13944 NC(nc_def_dim(ncid, "x", (size_t) met->nx, &lonid));
13945 NC(nc_def_dim(ncid, "y", (size_t) met->ny, &latid));
13946 NC_DEF_VAR("x", NC_DOUBLE, 1, &lonid, "x", "easting", 0, 0);
13947 NC_DEF_VAR("y", NC_DOUBLE, 1, &latid, "y", "northing", 0, 0);
13948 }
13949
13950 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
13951
13952 /* Define grid... */
13953 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
13954 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
13955 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
13956
13957 /* Define surface variables... */
13958 int dimid2[3] = { tid, latid, lonid };
13959 NC_DEF_VAR("sp", NC_FLOAT, 3, dimid2, "Surface pressure", "Pa",
13960 ctl->met_nc_level, 0);
13961 NC_DEF_VAR("z", NC_FLOAT, 3, dimid2, "Geopotential", "m**2 s**-2",
13962 ctl->met_nc_level, 0);
13963 NC_DEF_VAR("t2m", NC_FLOAT, 3, dimid2, "2 metre temperature", "K",
13964 ctl->met_nc_level, 0);
13965 NC_DEF_VAR("u10m", NC_FLOAT, 3, dimid2, "10 metre U wind component",
13966 "m s**-1", ctl->met_nc_level, 0);
13967 NC_DEF_VAR("v10m", NC_FLOAT, 3, dimid2, "10 metre V wind component",
13968 "m s**-1", ctl->met_nc_level, 0);
13969 NC_DEF_VAR("iews", NC_FLOAT, 3, dimid2,
13970 "Instantaneous eastward turbulent surface stress", "N m**-2",
13971 ctl->met_nc_level, 0);
13972 NC_DEF_VAR("inss", NC_FLOAT, 3, dimid2,
13973 "Instantaneous northward turbulent surface stress", "N m**-2",
13974 ctl->met_nc_level, 0);
13975 NC_DEF_VAR("ishf", NC_FLOAT, 3, dimid2,
13976 "Instantaneous surface sensible heat flux", "W m**-2",
13977 ctl->met_nc_level, 0);
13978 NC_DEF_VAR("lsm", NC_FLOAT, 3, dimid2, "Land/sea mask", "-",
13979 ctl->met_nc_level, 0);
13980 NC_DEF_VAR("sstk", NC_FLOAT, 3, dimid2, "Sea surface temperature", "K",
13981 ctl->met_nc_level, 0);
13982 NC_DEF_VAR("blp", NC_FLOAT, 3, dimid2, "Boundary layer pressure", "Pa",
13983 ctl->met_nc_level, 0);
13984 NC_DEF_VAR("pt", NC_FLOAT, 3, dimid2, "Tropopause pressure", "Pa",
13985 ctl->met_nc_level, 0);
13986 NC_DEF_VAR("tt", NC_FLOAT, 3, dimid2, "Tropopause temperature", "K",
13987 ctl->met_nc_level, 0);
13988 NC_DEF_VAR("zt", NC_FLOAT, 3, dimid2, "Tropopause height", "m",
13989 ctl->met_nc_level, 0);
13990 NC_DEF_VAR("h2ot", NC_FLOAT, 3, dimid2, "Tropopause water vapor", "ppv",
13991 ctl->met_nc_level, 0);
13992 NC_DEF_VAR("pct", NC_FLOAT, 3, dimid2, "Cloud top pressure", "Pa",
13993 ctl->met_nc_level, 0);
13994 NC_DEF_VAR("pcb", NC_FLOAT, 3, dimid2, "Cloud bottom pressure", "Pa",
13995 ctl->met_nc_level, 0);
13996 NC_DEF_VAR("cl", NC_FLOAT, 3, dimid2, "Total column cloud water",
13997 "kg m**2", ctl->met_nc_level, 0);
13998 NC_DEF_VAR("plcl", NC_FLOAT, 3, dimid2,
13999 "Pressure at lifted condensation level (LCL)", "Pa",
14000 ctl->met_nc_level, 0);
14001 NC_DEF_VAR("plfc", NC_FLOAT, 3, dimid2,
14002 "Pressure at level of free convection (LFC)", "Pa",
14003 ctl->met_nc_level, 0);
14004 NC_DEF_VAR("pel", NC_FLOAT, 3, dimid2,
14005 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
14006 0);
14007 NC_DEF_VAR("cape", NC_FLOAT, 3, dimid2,
14008 "Convective available potential energy", "J kg**-1",
14009 ctl->met_nc_level, 0);
14010 NC_DEF_VAR("cin", NC_FLOAT, 3, dimid2, "Convective inhibition",
14011 "J kg**-1", ctl->met_nc_level, 0);
14012 NC_DEF_VAR("o3c", NC_FLOAT, 3, dimid2, "Total column ozone", "DU",
14013 ctl->met_nc_level, 0);
14014
14015 /* Define level data... */
14016 int dimid3[4] = { tid, levid, latid, lonid };
14017 NC_DEF_VAR("t", NC_FLOAT, 4, dimid3, "Temperature", "K",
14018 ctl->met_nc_level, ctl->met_nc_quant);
14019 NC_DEF_VAR("u", NC_FLOAT, 4, dimid3, "U velocity", "m s**-1",
14020 ctl->met_nc_level, ctl->met_nc_quant);
14021 NC_DEF_VAR("v", NC_FLOAT, 4, dimid3, "V velocity", "m s**-1",
14022 ctl->met_nc_level, ctl->met_nc_quant);
14023 NC_DEF_VAR("w", NC_FLOAT, 4, dimid3, "Vertical velocity", "Pa s**-1",
14024 ctl->met_nc_level, ctl->met_nc_quant);
14025 NC_DEF_VAR("q", NC_FLOAT, 4, dimid3, "Specific humidity", "kg kg**-1",
14026 ctl->met_nc_level, ctl->met_nc_quant);
14027 NC_DEF_VAR("o3", NC_FLOAT, 4, dimid3, "Ozone mass mixing ratio",
14028 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14029 NC_DEF_VAR("clwc", NC_FLOAT, 4, dimid3, "Cloud liquid water content",
14030 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14031 NC_DEF_VAR("crwc", NC_FLOAT, 4, dimid3, "Cloud rain water content",
14032 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14033 NC_DEF_VAR("ciwc", NC_FLOAT, 4, dimid3, "Cloud ice water content",
14034 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14035 NC_DEF_VAR("cswc", NC_FLOAT, 4, dimid3, "Cloud snow water content",
14036 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14037 NC_DEF_VAR("cc", NC_FLOAT, 4, dimid3, "Cloud cover", "-",
14038 ctl->met_nc_level, ctl->met_nc_quant);
14039
14040 /* End definitions... */
14041 NC(nc_enddef(ncid));
14042
14043 /* Write grid data... */
14044 NC_PUT_DOUBLE("time", &met->time, 0);
14045
14046 if (met->coord_type == 0) {
14047 NC_PUT_DOUBLE("lon", met->lon, 0);
14048 NC_PUT_DOUBLE("lat", met->lat, 0);
14049 } else {
14050 NC_PUT_DOUBLE("x", met->lon, 0);
14051 NC_PUT_DOUBLE("y", met->lat, 0);
14052 }
14053
14054 double phelp[EP];
14055 for (int ip = 0; ip < met->np; ip++)
14056 phelp[ip] = 100. * met->p[ip];
14057 NC_PUT_DOUBLE("lev", phelp, 0);
14058
14059 /* Write surface data... */
14060 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
14061 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
14062 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
14063 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
14064 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
14065 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
14066 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
14067 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
14068 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
14069 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
14070 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
14071 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
14072 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
14073 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
14074 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
14075 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
14076 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
14077 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
14078 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
14079 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
14080 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
14081 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
14082 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
14083 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
14084
14085 /* Write level data... */
14086 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
14087 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
14088 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
14089 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
14090 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
14091 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
14092 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
14093 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
14094 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
14095 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
14096 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
14097
14098 /* Close file... */
14099 NC(nc_close(ncid));
14100}
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:14104
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:14134
Here is the call graph for this function:

◆ write_met_nc_2d()

void write_met_nc_2d ( const int  ncid,
const char *  varname,
met_t met,
float  var[EX][EY],
const float  scl 
)

Writes a 2D meteorological variable to a NetCDF file.

This function writes a 2D meteorological variable, stored in the array var, to a NetCDF file with the specified variable name. The data is scaled by a factor scl before being written. The function handles memory allocation for the data copy, scaling, and freeing the allocated memory after writing the data to the NetCDF file.

Parameters
ncidThe NetCDF file ID. This is an integer that identifies the NetCDF file where the data will be written. It is assumed that this file has already been opened for writing.
varnameA pointer to a string containing the name of the variable in the NetCDF file where the data will be stored.
metA pointer to a structure of type met_t that contains metadata about the meteorological field, including the dimensions nx (number of points in x-direction) and ny (number of points in y-direction).
varA 2D array of dimensions EX x EY containing the meteorological data to be written. The data is provided in the format var[ix][iy], where ix is the index in the x-direction and iy is the index in the y-direction.
sclA scaling factor applied to each element in the var array before writing to the NetCDF file.
Author
Lars Hoffmann

Definition at line 14104 of file mptrac.c.

14109 {
14110
14111 int varid;
14112 size_t start[4], count[4];
14113
14114 /* Allocate... */
14115 float *help;
14116 ALLOC(help, float,
14117 EX * EY);
14118
14119 /* Copy data... */
14120 for (int ix = 0; ix < met->nx; ix++)
14121 for (int iy = 0; iy < met->ny; iy++)
14122 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
14123
14124 /* Write data... */
14125 LOG(2, "Write 2-D variable: %s (netCDF)", varname);
14126 NC_PUT_FLOAT(varname, help, 0);
14127
14128 /* Free... */
14129 free(help);
14130}
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1435

◆ write_met_nc_3d()

void write_met_nc_3d ( const int  ncid,
const char *  varname,
met_t met,
float  var[EX][EY][EP],
const float  scl 
)

Writes a 3D meteorological variable to a NetCDF file.

This function writes a 3D meteorological variable, stored in the array var, to a NetCDF file with the specified variable name. The data is scaled by a factor scl before being written. The function handles memory allocation for the data copy, scaling, and freeing the allocated memory after writing the data to the NetCDF file.

Parameters
ncidThe NetCDF file ID. This is an integer that identifies the NetCDF file where the data will be written. It is assumed that this file has already been opened for writing.
varnameA pointer to a string containing the name of the variable in the NetCDF file where the data will be stored.
metA pointer to a structure of type met_t that contains metadata about the meteorological field, including the dimensions nx (number of points in the x-direction), ny (number of points in the y-direction), and np (number of points in the third dimension, e.g., pressure levels).
varA 3D array of dimensions EX x EY x EP containing the meteorological data to be written. The data is provided in the format var[ix][iy][ip], where ix is the index in the x-direction, iy is the index in the y-direction, and ip is the index in the third dimension (e.g., vertical levels).
sclA scaling factor applied to each element in the var array before writing to the NetCDF file.
Author
Lars Hoffmann

Definition at line 14134 of file mptrac.c.

14139 {
14140
14141 int varid;
14142 size_t start[4], count[4];
14143
14144 /* Allocate... */
14145 float *help;
14146 ALLOC(help, float,
14147 EX * EY * EP);
14148
14149 /* Copy data... */
14150 for (int ix = 0; ix < met->nx; ix++)
14151 for (int iy = 0; iy < met->ny; iy++)
14152 for (int ip = 0; ip < met->np; ip++)
14153 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
14154
14155 /* Write data... */
14156 LOG(2, "Write 3-D variable: %s (netCDF)", varname);
14157 NC_PUT_FLOAT(varname, help, 0);
14158
14159 /* Free... */
14160 free(help);
14161}

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

14171 {
14172
14173 if (ctl->met_coord_type != 0)
14174 ERRMSG("Only lat/lon grid supported");
14175
14176 static FILE *out;
14177
14178 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
14179 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
14180
14181 static int nobs, *obscount, ip, okay;
14182
14183 /* Set timer... */
14184 SELECT_TIMER("WRITE_PROF", "OUTPUT");
14185
14186 /* Init... */
14187 if (t == ctl->t_start) {
14188
14189 /* Check quantity index for mass... */
14190 if (ctl->qnt_m < 0)
14191 ERRMSG("Need quantity mass!");
14192
14193 /* Check molar mass... */
14194 if (ctl->molmass <= 0)
14195 ERRMSG("Specify molar mass!");
14196
14197 /* Allocate... */
14198 ALLOC(lon, double,
14199 ctl->prof_nx);
14200 ALLOC(lat, double,
14201 ctl->prof_ny);
14202 ALLOC(area, double,
14203 ctl->prof_ny);
14204 ALLOC(z, double,
14205 ctl->prof_nz);
14206 ALLOC(press, double,
14207 ctl->prof_nz);
14208 ALLOC(rt, double,
14209 NOBS);
14210 ALLOC(rz, double,
14211 NOBS);
14212 ALLOC(rlon, double,
14213 NOBS);
14214 ALLOC(rlat, double,
14215 NOBS);
14216 ALLOC(robs, double,
14217 NOBS);
14218
14219 /* Read observation data... */
14220 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
14221
14222 /* Create new output file... */
14223 LOG(1, "Write profile data: %s", filename);
14224 if (!(out = fopen(filename, "w")))
14225 ERRMSG("Cannot create file!");
14226
14227 /* Write header... */
14228 fprintf(out,
14229 "# $1 = time [s]\n"
14230 "# $2 = altitude [km]\n"
14231 "# $3 = longitude [deg]\n"
14232 "# $4 = latitude [deg]\n"
14233 "# $5 = pressure [hPa]\n"
14234 "# $6 = temperature [K]\n"
14235 "# $7 = volume mixing ratio [ppv]\n"
14236 "# $8 = H2O volume mixing ratio [ppv]\n"
14237 "# $9 = O3 volume mixing ratio [ppv]\n"
14238 "# $10 = observed BT index [K]\n"
14239 "# $11 = number of observations\n");
14240
14241 /* Set grid box size... */
14242 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
14243 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
14244 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
14245
14246 /* Set vertical coordinates... */
14247 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14248 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
14249 press[iz] = P(z[iz]);
14250 }
14251
14252 /* Set horizontal coordinates... */
14253 for (int ix = 0; ix < ctl->prof_nx; ix++)
14254 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
14255 for (int iy = 0; iy < ctl->prof_ny; iy++) {
14256 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
14257 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
14258 }
14259 }
14260
14261 /* Set time interval... */
14262 const double t0 = t - 0.5 * ctl->dt_mod;
14263 const double t1 = t + 0.5 * ctl->dt_mod;
14264
14265 /* Allocate... */
14266 ALLOC(mass, double,
14267 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
14268 ALLOC(obsmean, double,
14269 ctl->prof_nx * ctl->prof_ny);
14270 ALLOC(obscount, int,
14271 ctl->prof_nx * ctl->prof_ny);
14272
14273 /* Loop over observations... */
14274 for (int i = 0; i < nobs; i++) {
14275
14276 /* Check time... */
14277 if (rt[i] < t0)
14278 continue;
14279 else if (rt[i] >= t1)
14280 break;
14281
14282 /* Check observation data... */
14283 if (!isfinite(robs[i]))
14284 continue;
14285
14286 /* Calculate indices... */
14287 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
14288 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
14289
14290 /* Check indices... */
14291 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
14292 continue;
14293
14294 /* Get mean observation index... */
14295 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
14296 obsmean[idx] += robs[i];
14297 obscount[idx]++;
14298 }
14299
14300 /* Analyze model data... */
14301 for (ip = 0; ip < atm->np; ip++) {
14302
14303 /* Check time... */
14304 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14305 continue;
14306
14307 /* Get indices... */
14308 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
14309 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
14310 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
14311
14312 /* Check indices... */
14313 if (ix < 0 || ix >= ctl->prof_nx ||
14314 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
14315 continue;
14316
14317 /* Get total mass in grid cell... */
14318 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14319 mass[idx] += atm->q[ctl->qnt_m][ip];
14320 }
14321
14322 /* Extract profiles... */
14323 for (int ix = 0; ix < ctl->prof_nx; ix++)
14324 for (int iy = 0; iy < ctl->prof_ny; iy++) {
14325 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
14326 if (obscount[idx2] > 0) {
14327
14328 /* Check profile... */
14329 okay = 0;
14330 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14331 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14332 if (mass[idx3] > 0) {
14333 okay = 1;
14334 break;
14335 }
14336 }
14337 if (!okay)
14338 continue;
14339
14340 /* Write output... */
14341 fprintf(out, "\n");
14342
14343 /* Loop over altitudes... */
14344 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14345
14346 /* Get temperature, water vapor, and ozone... */
14348 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
14349 lon[ix], lat[iy], &temp, ci, cw, 1);
14350 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
14351 lon[ix], lat[iy], &h2o, ci, cw, 0);
14352 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
14353 lon[ix], lat[iy], &o3, ci, cw, 0);
14354
14355 /* Calculate volume mixing ratio... */
14356 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14357 vmr = MA / ctl->molmass * mass[idx3]
14358 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
14359
14360 /* Write output... */
14361 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
14362 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
14363 obsmean[idx2] / obscount[idx2], obscount[idx2]);
14364 }
14365 }
14366 }
14367
14368 /* Free... */
14369 free(mass);
14370 free(obsmean);
14371 free(obscount);
14372
14373 /* Finalize... */
14374 if (t == ctl->t_stop) {
14375
14376 /* Close output file... */
14377 fclose(out);
14378
14379 /* Free... */
14380 free(lon);
14381 free(lat);
14382 free(area);
14383 free(z);
14384 free(press);
14385 free(rt);
14386 free(rz);
14387 free(rlon);
14388 free(rlat);
14389 free(robs);
14390 }
14391}
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 14395 of file mptrac.c.

14401 {
14402
14403 if (ctl->met_coord_type != 0)
14404 ERRMSG("Only lat/lon grid supported");
14405
14406 static FILE *out;
14407
14408 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
14409 kw[EP];
14410
14411 static int nobs, nk;
14412
14413 /* Set timer... */
14414 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT");
14415
14416 /* Init... */
14417 if (t == ctl->t_start) {
14418
14419 /* Allocate... */
14420 ALLOC(rt, double,
14421 NOBS);
14422 ALLOC(rz, double,
14423 NOBS);
14424 ALLOC(rlon, double,
14425 NOBS);
14426 ALLOC(rlat, double,
14427 NOBS);
14428 ALLOC(robs, double,
14429 NOBS);
14430
14431 /* Read observation data... */
14432 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
14433
14434 /* Read kernel data... */
14435 if (ctl->sample_kernel[0] != '-')
14436 read_kernel(ctl->sample_kernel, kz, kw, &nk);
14437
14438 /* Create output file... */
14439 LOG(1, "Write sample data: %s", filename);
14440 if (!(out = fopen(filename, "w")))
14441 ERRMSG("Cannot create file!");
14442
14443 /* Write header... */
14444 fprintf(out,
14445 "# $1 = time [s]\n"
14446 "# $2 = altitude [km]\n"
14447 "# $3 = longitude [deg]\n"
14448 "# $4 = latitude [deg]\n"
14449 "# $5 = surface area [km^2]\n"
14450 "# $6 = layer depth [km]\n"
14451 "# $7 = number of particles [1]\n"
14452 "# $8 = column density [kg/m^2]\n"
14453 "# $9 = volume mixing ratio [ppv]\n"
14454 "# $10 = observed BT index [K]\n\n");
14455
14456 /* Set latitude range, squared radius, and area... */
14457 dlat = DY2DEG(ctl->sample_dx);
14458 rmax2 = SQR(ctl->sample_dx);
14459 area = M_PI * rmax2;
14460 }
14461
14462 /* Set time interval for output... */
14463 const double t0 = t - 0.5 * ctl->dt_mod;
14464 const double t1 = t + 0.5 * ctl->dt_mod;
14465
14466 /* Loop over observations... */
14467 for (int i = 0; i < nobs; i++) {
14468
14469 /* Check time... */
14470 if (rt[i] < t0)
14471 continue;
14472 else if (rt[i] >= t1)
14473 break;
14474
14475 /* Calculate Cartesian coordinates... */
14476 double x0[3];
14477 geo2cart(0, rlon[i], rlat[i], x0);
14478
14479 /* Set pressure range... */
14480 const double rp = P(rz[i]);
14481 const double ptop = P(rz[i] + ctl->sample_dz);
14482 const double pbot = P(rz[i] - ctl->sample_dz);
14483
14484 /* Init... */
14485 double mass = 0;
14486 int np = 0;
14487
14488 /* Loop over air parcels... */
14489 //#pragma omp parallel for default(shared) reduction(+:mass,np)
14490 for (int ip = 0; ip < atm->np; ip++) {
14491
14492 /* Check time... */
14493 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14494 continue;
14495
14496 /* Check latitude... */
14497 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
14498 continue;
14499
14500 /* Check horizontal distance... */
14501 double x1[3];
14502 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
14503 if (DIST2(x0, x1) > rmax2)
14504 continue;
14505
14506 /* Check pressure... */
14507 if (ctl->sample_dz > 0)
14508 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
14509 continue;
14510
14511 /* Add mass... */
14512 if (ctl->qnt_m >= 0)
14513 mass +=
14514 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
14515 np++;
14516 }
14517
14518 /* Calculate column density... */
14519 const double cd = mass / (1e6 * area);
14520
14521 /* Calculate volume mixing ratio... */
14522 double vmr = 0;
14523 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
14524 if (mass > 0) {
14525
14526 /* Get temperature... */
14527 double temp;
14529 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
14530 rlon[i], rlat[i], &temp, ci, cw, 1);
14531
14532 /* Calculate volume mixing ratio... */
14533 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
14534 }
14535 } else
14536 vmr = NAN;
14537
14538 /* Write output... */
14539 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
14540 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
14541 }
14542
14543 /* Finalize...... */
14544 if (t == ctl->t_stop) {
14545
14546 /* Close output file... */
14547 fclose(out);
14548
14549 /* Free... */
14550 free(rt);
14551 free(rz);
14552 free(rlon);
14553 free(rlat);
14554 free(robs);
14555 }
14556}
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 14560 of file mptrac.c.

14564 {
14565
14566 if (ctl->met_coord_type != 0)
14567 ERRMSG("Only lat/lon grid supported");
14568
14569 static FILE *out;
14570
14571 static double rmax2, x0[3], x1[3];
14572
14573 /* Set timer... */
14574 SELECT_TIMER("WRITE_STATION", "OUTPUT");
14575
14576 /* Init... */
14577 if (t == ctl->t_start) {
14578
14579 /* Write info... */
14580 LOG(1, "Write station data: %s", filename);
14581
14582 /* Create new file... */
14583 if (!(out = fopen(filename, "w")))
14584 ERRMSG("Cannot create file!");
14585
14586 /* Write header... */
14587 fprintf(out,
14588 "# $1 = time [s]\n"
14589 "# $2 = altitude [km]\n"
14590 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
14591 for (int iq = 0; iq < ctl->nq; iq++)
14592 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
14593 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
14594 fprintf(out, "\n");
14595
14596 /* Set geolocation and search radius... */
14597 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
14598 rmax2 = SQR(ctl->stat_r);
14599 }
14600
14601 /* Set time interval for output... */
14602 const double t0 = t - 0.5 * ctl->dt_mod;
14603 const double t1 = t + 0.5 * ctl->dt_mod;
14604
14605 /* Loop over air parcels... */
14606 for (int ip = 0; ip < atm->np; ip++) {
14607
14608 /* Check time... */
14609 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14610 continue;
14611
14612 /* Check time range for station output... */
14613 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
14614 continue;
14615
14616 /* Check station flag... */
14617 if (ctl->qnt_stat >= 0)
14618 if ((int) atm->q[ctl->qnt_stat][ip])
14619 continue;
14620
14621 /* Get Cartesian coordinates... */
14622 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
14623
14624 /* Check horizontal distance... */
14625 if (DIST2(x0, x1) > rmax2)
14626 continue;
14627
14628 /* Set station flag... */
14629 if (ctl->qnt_stat >= 0)
14630 atm->q[ctl->qnt_stat][ip] = 1;
14631
14632 /* Write data... */
14633 fprintf(out, "%.2f %g %g %g",
14634 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
14635 for (int iq = 0; iq < ctl->nq; iq++) {
14636 fprintf(out, " ");
14637 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
14638 }
14639 fprintf(out, "\n");
14640 }
14641
14642 /* Close file... */
14643 if (t == ctl->t_stop)
14644 fclose(out);
14645}
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 14649 of file mptrac.c.

14653 {
14654
14655 if (ctl->met_coord_type != 0)
14656 ERRMSG("Only lat/lon grid supported");
14657
14658 FILE *out;
14659
14660 /* Set timer... */
14661 SELECT_TIMER("WRITE_VTK", "OUTPUT");
14662
14663 /* Write info... */
14664 LOG(1, "Write VTK data: %s", filename);
14665
14666 /* Set time interval for output... */
14667 const double t0 = t - 0.5 * ctl->dt_mod;
14668 const double t1 = t + 0.5 * ctl->dt_mod;
14669
14670 /* Create file... */
14671 if (!(out = fopen(filename, "w")))
14672 ERRMSG("Cannot create file!");
14673
14674 /* Count data points... */
14675 int np = 0;
14676 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14677 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14678 continue;
14679 np++;
14680 }
14681
14682 /* Write header... */
14683 fprintf(out,
14684 "# vtk DataFile Version 3.0\n"
14685 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
14686
14687 /* Write point coordinates... */
14688 fprintf(out, "POINTS %d float\n", np);
14689 if (ctl->vtk_sphere) {
14690 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14691 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14692 continue;
14693 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
14694 + ctl->vtk_offset) / RE;
14695 const double coslat = cos(DEG2RAD(atm->lat[ip]));
14696 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
14697 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
14698 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
14699 fprintf(out, "%g %g %g\n", x, y, z);
14700 }
14701 } else
14702 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14703 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14704 continue;
14705 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
14706 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
14707 }
14708
14709 /* Write point data... */
14710 fprintf(out, "POINT_DATA %d\n", np);
14711 for (int iq = 0; iq < ctl->nq; iq++) {
14712 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
14713 ctl->qnt_name[iq]);
14714 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14715 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14716 continue;
14717 fprintf(out, "%g\n", atm->q[iq][ip]);
14718 }
14719 }
14720
14721 /* Close file... */
14722 fclose(out);
14723}