MPTRAC
Functions
mptrac.c File Reference

MPTRAC library definitions. More...

#include "mptrac.h"

Go to the source code of this file.

Functions

void cart2geo (const double *x, double *z, double *lon, double *lat)
 State variables of cuRAND random number generator. More...
 
double clim_oh (const ctl_t *ctl, const clim_t *clim, const double t, const double lon, const double lat, const double p)
 Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal correction based on solar zenith angle. More...
 
void clim_oh_diurnal_correction (const ctl_t *ctl, clim_t *clim)
 Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data. More...
 
double clim_photo (const double rate[CP][CSZA][CO3], const clim_photo_t *photo, const double p, const double sza, const double o3c)
 Calculates the photolysis rate for a given set of atmospheric conditions. More...
 
double clim_tropo (const clim_t *clim, const double t, const double lat)
 Calculates the tropopause pressure based on climatological data. More...
 
void clim_tropo_init (clim_t *clim)
 Initializes the tropopause data in the climatology structure. More...
 
double clim_ts (const clim_ts_t *ts, const double t)
 Interpolates a time series of climatological variables. More...
 
double clim_zm (const clim_zm_t *zm, const double t, const double lat, const double p)
 Interpolates monthly mean zonal mean climatological variables. More...
 
void compress_pck (const char *varname, float *array, const size_t nxy, const size_t nz, const int decompress, FILE *inout)
 Compresses or decompresses a 3D array of floats. More...
 
void day2doy (const int year, const int mon, const int day, int *doy)
 Get day of year from date. More...
 
void doy2day (const int year, const int doy, int *mon, int *day)
 Converts a given day of the year (DOY) to a date (month and day). More...
 
void fft_help (double *fcReal, double *fcImag, const int n)
 Computes the Fast Fourier Transform (FFT) of a complex sequence. More...
 
void geo2cart (const double z, const double lon, const double lat, double *x)
 Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates. More...
 
void get_met (ctl_t *ctl, clim_t *clim, const double t, met_t **met0, met_t **met1)
 Retrieves meteorological data for the specified time. More...
 
void get_met_help (const ctl_t *ctl, const double t, const int direct, const char *metbase, const double dt_met, char *filename)
 
void get_met_replace (char *orig, char *search, char *repl)
 Replaces occurrences of a substring in a string with another substring. More...
 
void get_tropo (const int met_tropo, ctl_t *ctl, clim_t *clim, met_t *met, const double *lons, const int nx, const double *lats, const int ny, double *pt, double *zt, double *tt, double *qt, double *o3t, double *ps, double *zs)
 Calculate tropopause data. More...
 
void intpol_met_4d_coord (const met_t *met0, float heights0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float heights1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double height, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological variables to a given position and time. More...
 
void intpol_met_space_3d (const met_t *met, float array[EX][EY][EP], const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological variables in 3D space. More...
 
void intpol_met_space_3d_ml (const met_t *met, float array[EX][EY][EP], const double p, const double lon, const double lat, double *var)
 Interpolates a meteorological variable in 3D space (longitude, latitude, pressure). More...
 
void intpol_met_space_2d (const met_t *met, float array[EX][EY], const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological variables in 2D space. More...
 
void intpol_met_time_3d (const met_t *met0, float array0[EX][EY][EP], const met_t *met1, float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
 Interpolates meteorological data in 3D space and time. More...
 
void intpol_met_time_3d_ml (const met_t *met0, float 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)
 Interpolates a meteorological variable in time and 3D space (longitude, latitude, pressure). 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, met_t *met0, met_t *met1, atm_t *atm, const double *dt)
 Performs the advection of atmospheric particles using meteorological data. More...
 
void module_advect_init (const ctl_t *ctl, 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 clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, const double *dt)
 Apply boundary conditions to particles based on meteorological and climatological data. More...
 
void module_chemgrid (const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double tt)
 Calculate grid data for chemistry modules. More...
 
void module_chem_init (const ctl_t *ctl, const 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, met_t *met0, met_t *met1, atm_t *atm, const double *dt, double *rs)
 Simulate convective processes for atmospheric particles. More...
 
void module_decay (const ctl_t *ctl, const clim_t *clim, atm_t *atm, const double *dt)
 Simulate exponential decay processes for atmospheric particles. More...
 
void module_diffusion_meso (const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, cache_t *cache, const double *dt, double *rs)
 Simulate mesoscale diffusion for atmospheric particles. More...
 
void module_diffusion_turb (const ctl_t *ctl, const clim_t *clim, atm_t *atm, const double *dt, double *rs)
 Simulate turbulent diffusion for atmospheric particles. More...
 
void module_dry_deposition (const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double *dt)
 Simulate dry deposition of atmospheric particles. More...
 
void module_h2o2_chem (const ctl_t *ctl, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, const double *dt)
 Perform chemical reactions involving H2O2 within cloud particles. More...
 
void module_isosurf_init (const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, cache_t *cache)
 Initialize the isosurface module based on atmospheric data. More...
 
void module_isosurf (const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, cache_t *cache, const double *dt)
 Apply the isosurface module to adjust atmospheric properties. More...
 
void module_meteo (const ctl_t *ctl, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, const double *dt)
 Update atmospheric properties using meteorological data. More...
 
void module_mixing (const ctl_t *ctl, const clim_t *clim, atm_t *atm, const double t)
 Update atmospheric properties through interparcel mixing. More...
 
void module_mixing_help (const ctl_t *ctl, const clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, const int qnt_idx)
 Perform interparcel mixing for a specific quantity. More...
 
void module_oh_chem (const ctl_t *ctl, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, const double *dt)
 Perform hydroxyl chemistry calculations for atmospheric particles. More...
 
void module_position (const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double *dt)
 Update the positions and pressure levels of atmospheric particles. More...
 
void module_rng_init (const int ntask)
 Initialize random number generators for parallel tasks. More...
 
void module_rng (const ctl_t *ctl, double *rs, const size_t n, const int method)
 Generate random numbers using various methods and distributions. More...
 
void module_sedi (const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double *dt)
 Simulate sedimentation of particles in the atmosphere. More...
 
void module_sort (const ctl_t *ctl, met_t *met0, atm_t *atm)
 Sort particles according to box index. More...
 
void module_sort_help (double *a, const int *p, const int np)
 Reorder an array based on a given permutation. More...
 
void module_timesteps (const ctl_t *ctl, met_t *met0, atm_t *atm, double *dt, 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 clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, const double *dt)
 Simulate chemical reactions involving long-lived atmospheric tracers. More...
 
void module_wet_deposition (const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double *dt)
 Perform wet deposition calculations for air parcels. More...
 
double nat_temperature (const double p, const double h2o, const double hno3)
 Calculates the nitric acid trihydrate (NAT) temperature. More...
 
int 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...
 
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 air parcel data from a CLaMS netCDF file and populates the given atmospheric structure. 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 (const ctl_t *ctl, clim_t *clim)
 Reads various climatological data and populates the given climatology 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_ctl (const char *filename, int argc, char *argv[], ctl_t *ctl)
 Reads control parameters from a configuration 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 (const char *filename, ctl_t *ctl, clim_t *clim, met_t *met)
 Reads meteorological data from a file, supporting multiple formats and MPI broadcasting. More...
 
int read_met_bin (const char *filename, ctl_t *ctl, met_t *met)
 Reads meteorological data from a binary file. More...
 
void read_met_bin_2d (FILE *in, const met_t *met, float var[EX][EY], const char *varname)
 Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array. More...
 
void read_met_bin_3d (FILE *in, const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname, const float bound_min, const float bound_max)
 Reads 3D meteorological data from a binary file, potentially using different compression methods. More...
 
void read_met_cape (const ctl_t *ctl, const clim_t *clim, met_t *met)
 Calculates Convective Available Potential Energy (CAPE) for each grid point. More...
 
void read_met_cloud (met_t *met)
 Calculates cloud-related variables for each grid point. More...
 
void read_met_detrend (const ctl_t *ctl, met_t *met)
 Detrends meteorological data. More...
 
void read_met_extrapolate (met_t *met)
 Extrapolates meteorological data. More...
 
void read_met_geopot (const ctl_t *ctl, met_t *met)
 Calculates geopotential heights from meteorological data. More...
 
void read_met_grid (const char *filename, const int ncid, const ctl_t *ctl, met_t *met)
 Reads meteorological grid information from a NetCDF file. More...
 
void read_met_levels (const int ncid, const ctl_t *ctl, met_t *met)
 Reads meteorological variables at different vertical levels from a NetCDF file. More...
 
void read_met_ml2pl (const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname)
 Interpolates meteorological data to specified pressure levels. More...
 
void read_met_monotonize (met_t *met)
 Makes zeta and pressure profiles monotone. More...
 
int read_met_nc (const char *filename, ctl_t *ctl, clim_t *clim, met_t *met)
 Reads meteorological data from a NetCDF file and processes it. More...
 
int read_met_nc_2d (const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const char *varname5, const char *varname6, const ctl_t *ctl, const met_t *met, float dest[EX][EY], const float scl, const int init)
 Reads a 2-dimensional meteorological variable from a NetCDF file. More...
 
int read_met_nc_3d (const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const ctl_t *ctl, const met_t *met, float dest[EX][EY][EP], const float scl)
 Reads a 3-dimensional meteorological variable from a NetCDF file. More...
 
void read_met_pbl (const ctl_t *ctl, met_t *met)
 Computes the planetary boundary layer (PBL) height based on meteorological data. More...
 
void read_met_periodic (met_t *met)
 Applies periodic boundary conditions to meteorological data along longitudinal axis. More...
 
void read_met_polar_winds (met_t *met)
 Applies a fix for polar winds in meteorological data. More...
 
void read_met_pv (met_t *met)
 Calculates potential vorticity (PV) from meteorological data. More...
 
void read_met_ozone (met_t *met)
 Calculates the total column ozone from meteorological ozone data. More...
 
void read_met_sample (const ctl_t *ctl, met_t *met)
 Downsamples meteorological data based on specified parameters. More...
 
void read_met_surface (const int ncid, const ctl_t *ctl, met_t *met)
 Reads surface meteorological data from a netCDF file and stores it in the meteorological data structure. More...
 
void read_met_tropo (const ctl_t *ctl, const clim_t *clim, met_t *met)
 Calculates the tropopause and related meteorological variables based on various methods and stores the results in the meteorological data structure. More...
 
void read_obs (const char *filename, const ctl_t *ctl, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
 Reads observation data from a file and stores it in arrays. More...
 
void read_obs_asc (const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
 Reads observation data from an ASCII file. More...
 
void read_obs_nc (const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
 Reads observation data from a NetCDF file. More...
 
double scan_ctl (const char *filename, int argc, char *argv[], const char *varname, const int arridx, const char *defvalue, char *value)
 Scans a control file or command-line arguments for a specified variable. More...
 
double sedi (const double p, const double T, const double rp, const double rhop)
 Calculates the sedimentation velocity of a particle in air. More...
 
void spline (const double *x, const double *y, const int n, const double *x2, double *y2, const int n2, const int method)
 Performs spline interpolation or linear interpolation. More...
 
float stddev (const float *data, const int n)
 Calculates the standard deviation of a set of data. More...
 
double sza_calc (const double sec, const double lon, const double lat)
 Calculates the solar zenith angle. More...
 
void time2jsec (const int year, const int mon, const int day, const int hour, const int min, const int sec, const double remain, double *jsec)
 Converts time components to seconds since January 1, 2000, 12:00:00 UTC. More...
 
void timer (const char *name, const char *group, const int output)
 Measures and reports elapsed time for named and grouped timers. More...
 
double time_from_filename (const char *filename, const int offset)
 Extracts and converts a timestamp from a filename to Julian seconds. More...
 
double tropo_weight (const clim_t *clim, const double t, const double lat, const double p)
 Computes the weighting factor for a given pressure with respect to the tropopause. More...
 
void 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 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 (const char *filename, const ctl_t *ctl, met_t *met)
 Writes meteorological data to a file, supporting multiple formats and compression options. More...
 
void write_met_bin (const char *filename, const ctl_t *ctl, met_t *met)
 Writes meteorological data in binary format to a specified file. More...
 
void write_met_bin_2d (FILE *out, met_t *met, float var[EX][EY], const char *varname)
 Writes a 2-dimensional meteorological variable to a binary file. More...
 
void write_met_bin_3d (FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int precision, const double tolerance)
 Writes a 3-dimensional meteorological variable to a binary file. More...
 
void write_met_nc (const char *filename, const ctl_t *ctl, met_t *met)
 Writes meteorological data to a NetCDF file. More...
 
void write_met_nc_2d (int ncid, const char *varname, met_t *met, float var[EX][EY], float scl)
 Writes a 2D meteorological variable to a NetCDF file. More...
 
void write_met_nc_3d (int ncid, const char *varname, met_t *met, float var[EX][EY][EP], float scl)
 Writes a 3D meteorological variable to a NetCDF file. More...
 
void 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...
 
void write_prof (const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
 Writes profile data to a specified file. More...
 
void write_sample (const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
 Writes sample data to a specified file. More...
 
void write_station (const char *filename, const ctl_t *ctl, atm_t *atm, const double t)
 Writes station data to a specified file. More...
 
void write_vtk (const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
 Writes VTK (Visualization Toolkit) data to a specified file. More...
 

Detailed Description

MPTRAC library definitions.

Definition in file mptrac.c.

Function Documentation

◆ cart2geo()

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

State variables of cuRAND random number generator.

Converts Cartesian coordinates to geographic coordinates.

Definition at line 74 of file mptrac.c.

78 {
79
80 const double radius = NORM(x);
81
82 *lat = RAD2DEG(asin(x[2] / radius));
83 *lon = RAD2DEG(atan2(x[1], x[0]));
84 *z = radius - RE;
85}
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:217
#define NORM(a)
Compute the norm (magnitude) of a vector.
Definition: mptrac.h:1232
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1381

◆ clim_oh()

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

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

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

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

Definition at line 89 of file mptrac.c.

95 {
96
97 /* Set SZA threshold... */
98 const double sza_thresh = DEG2RAD(85.), cos_sza_thresh = cos(sza_thresh);
99
100 /* Get OH data from climatology... */
101 const double oh = clim_zm(&clim->oh, t, lat, p);
102
103 /* Apply diurnal correction... */
104 if (ctl->oh_chem_beta > 0) {
105 double sza = sza_calc(t, lon, lat);
106 if (sza <= sza_thresh)
107 return oh * exp(-ctl->oh_chem_beta / cos(sza));
108 else
109 return oh * exp(-ctl->oh_chem_beta / cos_sza_thresh);
110 } else
111 return oh;
112}
double clim_zm(const clim_zm_t *zm, const double t, const double lat, const double p)
Interpolates monthly mean zonal mean climatological variables.
Definition: mptrac.c:401
double sza_calc(const double sec, const double lon, const double lat)
Calculates the solar zenith angle.
Definition: mptrac.c:8273
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:476
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3306
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2831
Here is the call graph for this function:

◆ clim_oh_diurnal_correction()

void clim_oh_diurnal_correction ( const ctl_t ctl,
clim_t clim 
)

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

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

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

Definition at line 116 of file mptrac.c.

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

◆ clim_photo()

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

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

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

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

This function performs the following steps:

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

Definition at line 149 of file mptrac.c.

154 {
155
156 /* Check pressure range... */
157 double p_help = p;
158 if (p < photo->p[photo->np - 1])
159 p_help = photo->p[photo->np - 1];
160 else if (p > photo->p[0])
161 p_help = photo->p[0];
162
163 /* Check sza range... */
164 double sza_help = sza;
165 if (sza < photo->sza[0])
166 sza_help = photo->sza[0];
167 else if (sza > photo->sza[photo->nsza - 1])
168 sza_help = photo->sza[photo->nsza - 1];
169
170 /* Check ozone column range... */
171 double o3c_help = o3c;
172 if (o3c < photo->o3c[0])
173 o3c_help = photo->o3c[0];
174 else if (o3c > photo->o3c[photo->no3c - 1])
175 o3c_help = photo->o3c[photo->no3c - 1];
176
177 /* Get indices... */
178 const int ip = locate_irr(photo->p, photo->np, p_help);
179 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
180 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
181
182 /* Interpolate photolysis rate... */
183 double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
184 photo->p[ip + 1], rate[ip + 1][isza][io3c], p_help);
185 double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
186 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1], p_help);
187 double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
188 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c], p_help);
189 double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
190 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
191 p_help);
192 aux00 = LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
193 aux11 = LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
194 aux00 = LIN(photo->sza[isza], aux00, photo->sza[isza + 1], aux11, sza_help);
195 return MAX(aux00, 0.0);
196}
int locate_reg(const double *xx, const int n, const double x)
Locate the index of the interval containing a given value in a regular grid.
Definition: mptrac.c:2180
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:2116
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:847
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:874
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3180
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3189
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3186
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3192
int np
Number of pressure levels.
Definition: mptrac.h:3177
int no3c
Number of total ozone columns.
Definition: mptrac.h:3183
Here is the call graph for this function:

◆ clim_tropo()

double clim_tropo ( const clim_t clim,
const double  t,
const double  lat 
)

Calculates the tropopause pressure based on climatological data.

This function computes the tropopause pressure using climatological data for different times and latitudes. It interpolates the tropopause pressure based on the input time and latitude parameters.

Parameters
climPointer to the climatology structure containing tropopause pressure data.
tTime for which the tropopause pressure is to be calculated, in seconds since the beginning of the year.
latLatitude at which the tropopause pressure is to be calculated.
Returns
The interpolated tropopause pressure for the specified time and latitude.

This function performs the following steps:

  1. Calculates the number of seconds since the beginning of the year.
  2. Determines the appropriate indices in the climatology data for interpolation based on time and latitude.
  3. Interpolates the tropopause pressure using linear interpolation based on latitude and time.
Author
Lars Hoffmann

Definition at line 200 of file mptrac.c.

203 {
204
205 /* Get seconds since begin of year... */
206 double sec = FMOD(t, 365.25 * 86400.);
207 while (sec < 0)
208 sec += 365.25 * 86400.;
209
210 /* Get indices... */
211 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
212 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
213
214 /* Interpolate tropopause pressure... */
215 const double p0 = LIN(clim->tropo_lat[ilat],
216 clim->tropo[isec][ilat],
217 clim->tropo_lat[ilat + 1],
218 clim->tropo[isec][ilat + 1], lat);
219 const double p1 = LIN(clim->tropo_lat[ilat],
220 clim->tropo[isec + 1][ilat],
221 clim->tropo_lat[ilat + 1],
222 clim->tropo[isec + 1][ilat + 1], lat);
223 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
224}
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:623
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3285
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3294
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3288
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3297
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3291
Here is the call graph for this function:

◆ clim_tropo_init()

void clim_tropo_init ( clim_t clim)

Initializes the tropopause data in the climatology structure.

This function initializes the tropopause data in the climatology structure. It sets the time steps, latitudes, and tropopause pressure values based on predefined arrays.

Parameters
climPointer to the climatology structure to be initialized.

This function performs the following steps:

  1. Sets the number of time steps and initializes the time array.
  2. Sets the number of latitudes and initializes the latitude array.
  3. Initializes the tropopause pressure values based on predefined arrays.
  4. Computes the range of tropopause pressure values.
  5. Logs information about the initialization process.
Author
Lars Hoffmann

Definition at line 228 of file mptrac.c.

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

◆ clim_ts()

double clim_ts ( const clim_ts_t ts,
const double  t 
)

Interpolates a time series of climatological variables.

This function interpolates a time series of climatological variables based on the input time and the provided data points.

Parameters
tsPointer to the time series structure containing data points.
tTime at which to interpolate the climatological variable (in seconds).
Returns
Interpolated value of the climatological variable at the given time.

This function performs linear interpolation between the closest data points to the input time t. If t is outside the range of the provided time series, the value at the nearest boundary is returned.

Author
Lars Hoffmann

Definition at line 383 of file mptrac.c.

385 {
386
387 /* Interpolate... */
388 if (t <= ts->time[0])
389 return ts->vmr[0];
390 else if (t >= ts->time[ts->ntime - 1])
391 return ts->vmr[ts->ntime - 1];
392 else {
393 int idx = locate_irr(ts->time, ts->ntime, t);
394 return LIN(ts->time[idx], ts->vmr[idx],
395 ts->time[idx + 1], ts->vmr[idx + 1], t);
396 }
397}
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3239
double time[CTS]
Time [s].
Definition: mptrac.h:3236
int ntime
Number of timesteps.
Definition: mptrac.h:3233
Here is the call graph for this function:

◆ clim_zm()

double clim_zm ( const clim_zm_t zm,
const double  t,
const double  lat,
const double  p 
)

Interpolates monthly mean zonal mean climatological variables.

This function interpolates climatological variables based on pressure, latitude, and time. The climatological data is provided in the form of monthly mean zonal mean values.

Parameters
zmPointer to the climatological zonal mean structure containing data points.
tTime at which to interpolate the climatological variable (in seconds since the beginning of the year).
latLatitude at which to interpolate the climatological variable (in degrees).
pPressure at which to interpolate the climatological variable (in hPa).
Returns
Interpolated value of the climatological variable at the given pressure, latitude, and time.

This function performs trilinear interpolation between the nearest data points to the input time t, latitude lat, and pressure or altitude p. If the input values are outside the range of the provided data, the function extrapolates by using the nearest boundary values.

Author
Lars Hoffmann

Definition at line 401 of file mptrac.c.

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

◆ compress_pck()

void compress_pck ( const char *  varname,
float *  array,
const size_t  nxy,
const size_t  nz,
const int  decompress,
FILE *  inout 
)

Compresses or decompresses a 3D array of floats.

This function either compresses or decompresses a 3D array of floats based on the value of the decompress parameter. Compression reduces the storage size by converting float values (4 bytes) to unsigned short values (2 bytes) with scaling and offset. Decompression restores the original float values from the compressed unsigned short representation.

Parameters
varnameThe name of the variable being processed.
arrayPointer to the 3D array of floats to be compressed or decompressed.
nxyThe number of elements in the first two dimensions of the array.
nzThe number of elements in the third dimension of the array.
decompressIf non-zero, the function will decompress the data; otherwise, it will compress the data.
inoutFile pointer for input or output operations. It is used for reading compressed data during decompression and writing compressed data during compression.

The function performs the following steps:

  • If decompressing:
    • Reads scaling factors, offsets, and compressed data from the file.
    • Decompresses the data and stores it in the array.
  • If compressing:
    • Computes the minimum and maximum values for each slice in the third dimension.
    • Calculates scaling factors and offsets based on these values.
    • Compresses the data by converting floats to unsigned shorts using the scaling factors and offsets.
    • Writes the scaling factors, offsets, and compressed data to the file.

The function allocates memory for the compressed data array and frees it before returning.

Author
Lars Hoffmann

Definition at line 657 of file mptrac.c.

663 {
664
665 double min[EP], max[EP], off[EP], scl[EP];
666
667 unsigned short *sarray;
668
669 /* Allocate... */
670 ALLOC(sarray, unsigned short,
671 nxy * nz);
672
673 /* Read compressed stream and decompress array... */
674 if (decompress) {
675
676 /* Write info... */
677 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
678 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
679
680 /* Read data... */
681 FREAD(&scl, double,
682 nz,
683 inout);
684 FREAD(&off, double,
685 nz,
686 inout);
687 FREAD(sarray, unsigned short,
688 nxy * nz,
689 inout);
690
691 /* Convert to float... */
692#pragma omp parallel for default(shared)
693 for (size_t ixy = 0; ixy < nxy; ixy++)
694 for (size_t iz = 0; iz < nz; iz++)
695 array[ixy * nz + iz]
696 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
697 }
698
699 /* Compress array and output compressed stream... */
700 else {
701
702 /* Write info... */
703 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
704 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
705
706 /* Get range... */
707 for (size_t iz = 0; iz < nz; iz++) {
708 min[iz] = array[iz];
709 max[iz] = array[iz];
710 }
711 for (size_t ixy = 1; ixy < nxy; ixy++)
712 for (size_t iz = 0; iz < nz; iz++) {
713 if (array[ixy * nz + iz] < min[iz])
714 min[iz] = array[ixy * nz + iz];
715 if (array[ixy * nz + iz] > max[iz])
716 max[iz] = array[ixy * nz + iz];
717 }
718
719 /* Get offset and scaling factor... */
720 for (size_t iz = 0; iz < nz; iz++) {
721 scl[iz] = (max[iz] - min[iz]) / 65533.;
722 off[iz] = min[iz];
723 }
724
725 /* Convert to short... */
726#pragma omp parallel for default(shared)
727 for (size_t ixy = 0; ixy < nxy; ixy++)
728 for (size_t iz = 0; iz < nz; iz++)
729 if (scl[iz] != 0)
730 sarray[ixy * nz + iz] = (unsigned short)
731 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
732 else
733 sarray[ixy * nz + iz] = 0;
734
735 /* Write data... */
736 FWRITE(&scl, double,
737 nz,
738 inout);
739 FWRITE(&off, double,
740 nz,
741 inout);
742 FWRITE(sarray, unsigned short,
743 nxy * nz,
744 inout);
745 }
746
747 /* Free... */
748 free(sarray);
749}
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:661
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:641
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:347
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:257

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

901 {
902
903 const int
904 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
905 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
906
907 /* Get day of year... */
908 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
909 *doy = d0l[mon - 1] + day - 1;
910 else
911 *doy = d0[mon - 1] + day - 1;
912}

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

920 {
921
922 const int
923 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
924 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
925
926 int i;
927
928 /* Get month and day... */
929 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
930 for (i = 11; i > 0; i--)
931 if (d0l[i] <= doy)
932 break;
933 *mon = i + 1;
934 *day = doy - d0l[i] + 1;
935 } else {
936 for (i = 11; i > 0; i--)
937 if (d0[i] <= doy)
938 break;
939 *mon = i + 1;
940 *day = doy - d0[i] + 1;
941 }
942}

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

949 {
950
951 gsl_fft_complex_wavetable *wavetable;
952 gsl_fft_complex_workspace *workspace;
953
954 double data[2 * EX];
955
956 /* Check size... */
957 if (n > EX)
958 ERRMSG("Too many data points!");
959
960 /* Allocate... */
961 wavetable = gsl_fft_complex_wavetable_alloc((size_t) n);
962 workspace = gsl_fft_complex_workspace_alloc((size_t) n);
963
964 /* Set data (real, complex)... */
965 for (int i = 0; i < n; i++) {
966 data[2 * i] = fcReal[i];
967 data[2 * i + 1] = fcImag[i];
968 }
969
970 /* Calculate FFT... */
971 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
972
973 /* Copy data... */
974 for (int i = 0; i < n; i++) {
975 fcReal[i] = data[2 * i];
976 fcImag[i] = data[2 * i + 1];
977 }
978
979 /* Free... */
980 gsl_fft_complex_wavetable_free(wavetable);
981 gsl_fft_complex_workspace_free(workspace);
982}
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:1901
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:262

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

990 {
991
992 const double radius = z + RE;
993 const double latrad = DEG2RAD(lat);
994 const double lonrad = DEG2RAD(lon);
995 const double coslat = cos(latrad);
996
997 x[0] = radius * coslat * cos(lonrad);
998 x[1] = radius * coslat * sin(lonrad);
999 x[2] = radius * sin(latrad);
1000}

◆ get_met()

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

Retrieves meteorological data for the specified time.

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

Parameters
ctlPointer to the control structure containing configuration settings.
climPointer to the climate structure.
tThe current time for which meteorological data is to be retrieved.
met0Pointer to the pointer of the first meteorological data structure.
met1Pointer to the pointer of the second meteorological data structure.

The function performs the following steps:

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

Definition at line 1004 of file mptrac.c.

1009 {
1010
1011 static int init;
1012
1013 met_t *mets;
1014
1015 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
1016
1017 /* Set timer... */
1018 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1019
1020 /* Init... */
1021 if (t == ctl->t_start || !init) {
1022 init = 1;
1023
1024 /* Read meteo data... */
1025 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
1026 ctl->metbase, ctl->dt_met, filename);
1027 if (!read_met(filename, ctl, clim, *met0))
1028 ERRMSG("Cannot open file!");
1029
1030 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
1031 ctl->metbase, ctl->dt_met, filename);
1032 if (!read_met(filename, ctl, clim, *met1))
1033 ERRMSG("Cannot open file!");
1034
1035 /* Update GPU... */
1036#ifdef _OPENACC
1037 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
1038 met_t *met0up = *met0;
1039 met_t *met1up = *met1;
1040#ifdef ASYNCIO
1041#pragma acc update device(met0up[:1],met1up[:1]) async(5)
1042#else
1043#pragma acc update device(met0up[:1],met1up[:1])
1044#endif
1045 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1046#endif
1047
1048 /* Caching... */
1049 if (ctl->met_cache && t != ctl->t_stop) {
1050 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
1051 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
1052 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1053 LOG(1, "Caching: %s", cachefile);
1054 if (system(cmd) != 0)
1055 WARN("Caching command failed!");
1056 }
1057 }
1058
1059 /* Read new data for forward trajectories... */
1060 if (t > (*met1)->time) {
1061
1062 /* Pointer swap... */
1063 mets = *met1;
1064 *met1 = *met0;
1065 *met0 = mets;
1066
1067 /* Read new meteo data... */
1068 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
1069 if (!read_met(filename, ctl, clim, *met1))
1070 ERRMSG("Cannot open file!");
1071
1072 /* Update GPU... */
1073#ifdef _OPENACC
1074 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
1075 met_t *met1up = *met1;
1076#ifdef ASYNCIO
1077#pragma acc update device(met1up[:1]) async(5)
1078#else
1079#pragma acc update device(met1up[:1])
1080#endif
1081 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1082#endif
1083
1084 /* Caching... */
1085 if (ctl->met_cache && t != ctl->t_stop) {
1086 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
1087 cachefile);
1088 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1089 LOG(1, "Caching: %s", cachefile);
1090 if (system(cmd) != 0)
1091 WARN("Caching command failed!");
1092 }
1093 }
1094
1095 /* Read new data for backward trajectories... */
1096 if (t < (*met0)->time) {
1097
1098 /* Pointer swap... */
1099 mets = *met1;
1100 *met1 = *met0;
1101 *met0 = mets;
1102
1103 /* Read new meteo data... */
1104 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
1105 if (!read_met(filename, ctl, clim, *met0))
1106 ERRMSG("Cannot open file!");
1107
1108 /* Update GPU... */
1109#ifdef _OPENACC
1110 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
1111 met_t *met0up = *met0;
1112#ifdef ASYNCIO
1113#pragma acc update device(met0up[:1]) async(5)
1114#else
1115#pragma acc update device(met0up[:1])
1116#endif
1117 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1118#endif
1119
1120 /* Caching... */
1121 if (ctl->met_cache && t != ctl->t_stop) {
1122 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
1123 cachefile);
1124 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1125 LOG(1, "Caching: %s", cachefile);
1126 if (system(cmd) != 0)
1127 WARN("Caching command failed!");
1128 }
1129 }
1130
1131 /* Check that grids are consistent... */
1132 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
1133 if ((*met0)->nx != (*met1)->nx
1134 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
1135 ERRMSG("Meteo grid dimensions do not match!");
1136 for (int ix = 0; ix < (*met0)->nx; ix++)
1137 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
1138 ERRMSG("Meteo grid longitudes do not match!");
1139 for (int iy = 0; iy < (*met0)->ny; iy++)
1140 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
1141 ERRMSG("Meteo grid latitudes do not match!");
1142 for (int ip = 0; ip < (*met0)->np; ip++)
1143 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
1144 ERRMSG("Meteo grid pressure levels do not match!");
1145 }
1146}
void get_met_help(const ctl_t *ctl, const double t, const int direct, const char *metbase, const double dt_met, char *filename)
Definition: mptrac.c:1150
int read_met(const char *filename, ctl_t *ctl, clim_t *clim, met_t *met)
Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.
Definition: mptrac.c:5655
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:236
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:1868
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:1981
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2459
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2478
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2465
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2616
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2475
double t_start
Start time of simulation [s].
Definition: mptrac.h:2462
Meteo data structure.
Definition: mptrac.h:3341
Here is the call graph for this function:

◆ get_met_help()

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

Definition at line 1150 of file mptrac.c.

1156 {
1157
1158 char repl[LEN];
1159
1160 double t6, r;
1161
1162 int year, mon, day, hour, min, sec;
1163
1164 /* Round time to fixed intervals... */
1165 if (direct == -1)
1166 t6 = floor(t / dt_met) * dt_met;
1167 else
1168 t6 = ceil(t / dt_met) * dt_met;
1169
1170 /* Decode time... */
1171 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1172
1173 /* Set filename of MPTRAC meteo files... */
1174 if (ctl->met_clams == 0) {
1175 if (ctl->met_type == 0)
1176 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1177 else if (ctl->met_type == 1)
1178 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1179 else if (ctl->met_type == 2)
1180 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1181 else if (ctl->met_type == 3)
1182 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1183 else if (ctl->met_type == 4)
1184 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1185 else if (ctl->met_type == 5)
1186 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1187 sprintf(repl, "%d", year);
1188 get_met_replace(filename, "YYYY", repl);
1189 sprintf(repl, "%02d", mon);
1190 get_met_replace(filename, "MM", repl);
1191 sprintf(repl, "%02d", day);
1192 get_met_replace(filename, "DD", repl);
1193 sprintf(repl, "%02d", hour);
1194 get_met_replace(filename, "HH", repl);
1195 }
1196
1197 /* Set filename of CLaMS meteo files... */
1198 else {
1199 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1200 sprintf(repl, "%d", year);
1201 get_met_replace(filename, "YYYY", repl);
1202 sprintf(repl, "%02d", year % 100);
1203 get_met_replace(filename, "YY", repl);
1204 sprintf(repl, "%02d", mon);
1205 get_met_replace(filename, "MM", repl);
1206 sprintf(repl, "%02d", day);
1207 get_met_replace(filename, "DD", repl);
1208 sprintf(repl, "%02d", hour);
1209 get_met_replace(filename, "HH", repl);
1210 }
1211}
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:1215
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:1832
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2173
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=zfp, 4=zstd, 5=cms).
Definition: mptrac.h:2485
Here is the call graph for this function:

◆ get_met_replace()

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

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

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

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

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

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

Definition at line 1215 of file mptrac.c.

1218 {
1219
1220 char buffer[LEN];
1221
1222 /* Iterate... */
1223 for (int i = 0; i < 3; i++) {
1224
1225 /* Replace sub-string... */
1226 char *ch;
1227 if (!(ch = strstr(orig, search)))
1228 return;
1229 strncpy(buffer, orig, (size_t) (ch - orig));
1230 buffer[ch - orig] = 0;
1231 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1232 orig[0] = 0;
1233 strcpy(orig, buffer);
1234 }
1235}

◆ get_tropo()

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

Calculate tropopause data.

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

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

Definition at line 1239 of file mptrac.c.

1254 {
1255
1257
1258 ctl->met_tropo = met_tropo;
1259 read_met_tropo(ctl, clim, met);
1260#pragma omp parallel for default(shared) private(ci,cw)
1261 for (int ix = 0; ix < nx; ix++)
1262 for (int iy = 0; iy < ny; iy++) {
1263 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1264 &pt[iy * nx + ix], ci, cw, 1);
1265 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1266 &ps[iy * nx + ix], ci, cw, 0);
1267 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1268 &zs[iy * nx + ix], ci, cw, 0);
1269 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1270 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1271 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1272 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1273 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1274 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1275 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1276 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1277 }
1278}
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:1593
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:7825
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:1460
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:676
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2601
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3452
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3371
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3377
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3455
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3437
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3395
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3434
Here is the call graph for this function:

◆ intpol_met_4d_coord()

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

Interpolates meteorological variables to a given position and time.

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

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

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

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

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

Definition at line 1282 of file mptrac.c.

1296 {
1297
1298 if (init) {
1299
1300 /* Check longitude... */
1301 double lon2 = FMOD(lon, 360.);
1302 if (lon2 < met0->lon[0])
1303 lon2 += 360;
1304 else if (lon2 > met0->lon[met0->nx - 1])
1305 lon2 -= 360;
1306
1307 /* Get horizontal indizes... */
1308 ci[0] = locate_irr(met0->lon, met0->nx, lon2);
1309 ci[1] = locate_irr(met0->lat, met0->ny, lat);
1310
1311 /* Locate the vertical indizes for each edge of the column... */
1312 int ind[2][4];
1313 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1314 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1315
1316 /* Find minimum and maximum indizes... */
1317 ci[2] = ind[0][0];
1318 int k_max = ind[0][0];
1319 for (int i = 0; i < 2; i++)
1320 for (int j = 0; j < 4; j++) {
1321 if (ci[2] > ind[i][j])
1322 ci[2] = ind[i][j];
1323 if (k_max < ind[i][j])
1324 k_max = ind[i][j];
1325 }
1326
1327 /* Get weighting factors for time, longitude and latitude... */
1328 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1329 cw[0] = (lon2 - met0->lon[ci[0]]) /
1330 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1331 cw[1] = (lat - met0->lat[ci[1]]) /
1332 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1333
1334 /* Start determiniation of the altitude weighting factor... */
1335 double height_top, height_bot;
1336 double height00, height01, height10, height11, height0, height1;
1337
1338 /* Interpolate in time at the lowest level... */
1339 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1340 - heights0[ci[0]][ci[1]][ci[2]])
1341 + heights0[ci[0]][ci[1]][ci[2]];
1342 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1343 - heights0[ci[0]][ci[1] + 1][ci[2]])
1344 + heights0[ci[0]][ci[1] + 1][ci[2]];
1345 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1346 - heights0[ci[0] + 1][ci[1]][ci[2]])
1347 + heights0[ci[0] + 1][ci[1]][ci[2]];
1348 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1349 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1350 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1351
1352 /* Interpolate in latitude direction... */
1353 height0 = cw[1] * (height01 - height00) + height00;
1354 height1 = cw[1] * (height11 - height10) + height10;
1355
1356 /* Interpolate in longitude direction... */
1357 height_bot = cw[0] * (height1 - height0) + height0;
1358
1359 /* Interpolate in time at the upper level... */
1360 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1361 - heights0[ci[0]][ci[1]][ci[2] + 1])
1362 + heights0[ci[0]][ci[1]][ci[2] + 1];
1363 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1364 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1365 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1366 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1367 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1368 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1369 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1370 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1371 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1372
1373 /* Interpolate in latitude direction... */
1374 height0 = cw[1] * (height01 - height00) + height00;
1375 height1 = cw[1] * (height11 - height10) + height10;
1376
1377 /* Interpolate in longitude direction... */
1378 height_top = cw[0] * (height1 - height0) + height0;
1379
1380 /* Search at higher levels if height is not in box... */
1381 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1382 ((height_bot <= height) || (height_top > height))
1383 && (height_bot >= height) && (ci[2] < k_max))
1384 ||
1385 ((heights0[0][0][0] < heights0[0][0][1]) &&
1386 ((height_bot >= height) || (height_top < height))
1387 && (height_bot <= height) && (ci[2] < k_max))
1388 ) {
1389
1390 ci[2]++;
1391 height_bot = height_top;
1392
1393 /* Interpolate in time at the next level... */
1394 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1395 - heights0[ci[0]][ci[1]][ci[2] + 1])
1396 + heights0[ci[0]][ci[1]][ci[2] + 1];
1397 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1398 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1399 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1400 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1401 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1402 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1403 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1404 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1405 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1406
1407 /* Interpolate in latitude direction... */
1408 height0 = cw[1] * (height01 - height00) + height00;
1409 height1 = cw[1] * (height11 - height10) + height10;
1410
1411 /* Interpolate in longitude direction... */
1412 height_top = cw[0] * (height1 - height0) + height0;
1413 }
1414
1415 /* Get vertical weighting factors... */
1416 cw[2] = (height - height_bot)
1417 / (height_top - height_bot);
1418 }
1419
1420 /* Calculate the needed array values... */
1421 double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1422 - array0[ci[0]][ci[1]][ci[2]])
1423 + array0[ci[0]][ci[1]][ci[2]];
1424 double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1425 - array0[ci[0] + 1][ci[1]][ci[2]])
1426 + array0[ci[0] + 1][ci[1]][ci[2]];
1427 double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1428 - array0[ci[0]][ci[1] + 1][ci[2]])
1429 + array0[ci[0]][ci[1] + 1][ci[2]];
1430 double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1431 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1432 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1433 double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1434 - array0[ci[0]][ci[1]][ci[2] + 1])
1435 + array0[ci[0]][ci[1]][ci[2] + 1];
1436 double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
1437 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
1438 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
1439 double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
1440 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
1441 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
1442 double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1443 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1444 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1445
1446 double array00 = cw[0] * (array100 - array000) + array000;
1447 double array10 = cw[0] * (array110 - array010) + array010;
1448 double array01 = cw[0] * (array101 - array001) + array001;
1449 double array11 = cw[0] * (array111 - array011) + array011;
1450
1451 double aux0 = cw[1] * (array10 - array00) + array00;
1452 double aux1 = cw[1] * (array11 - array01) + array01;
1453
1454 /* Interpolate vertically... */
1455 *var = cw[2] * (aux1 - aux0) + aux0;
1456}
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:2199
int nx
Number of longitudes.
Definition: mptrac.h:3347
int ny
Number of latitudes.
Definition: mptrac.h:3350
double lon[EX]
Longitude [deg].
Definition: mptrac.h:3359
int npl
Number of model levels.
Definition: mptrac.h:3356
double time
Time [s].
Definition: mptrac.h:3344
double lat[EY]
Latitude [deg].
Definition: mptrac.h:3362
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 1460 of file mptrac.c.

1469 {
1470
1471 /* Initialize interpolation... */
1472 if (init) {
1473
1474 /* Check longitude... */
1475 double lon2 = FMOD(lon, 360.);
1476 if (lon2 < met->lon[0])
1477 lon2 += 360;
1478 else if (lon2 > met->lon[met->nx - 1])
1479 lon2 -= 360;
1480
1481 /* Get interpolation indices... */
1482 ci[0] = locate_irr(met->p, met->np, p);
1483 ci[1] = locate_reg(met->lon, met->nx, lon2);
1484 ci[2] = locate_reg(met->lat, met->ny, lat);
1485
1486 /* Get interpolation weights... */
1487 cw[0] = (met->p[ci[0] + 1] - p)
1488 / (met->p[ci[0] + 1] - met->p[ci[0]]);
1489 cw[1] = (met->lon[ci[1] + 1] - lon2)
1490 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1491 cw[2] = (met->lat[ci[2] + 1] - lat)
1492 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1493 }
1494
1495 /* Interpolate vertically... */
1496 double aux00 =
1497 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
1498 + array[ci[1]][ci[2]][ci[0] + 1];
1499 double aux01 =
1500 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
1501 array[ci[1]][ci[2] + 1][ci[0] + 1])
1502 + array[ci[1]][ci[2] + 1][ci[0] + 1];
1503 double aux10 =
1504 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
1505 array[ci[1] + 1][ci[2]][ci[0] + 1])
1506 + array[ci[1] + 1][ci[2]][ci[0] + 1];
1507 double aux11 =
1508 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
1509 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
1510 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
1511
1512 /* Interpolate horizontally... */
1513 aux00 = cw[2] * (aux00 - aux01) + aux01;
1514 aux11 = cw[2] * (aux10 - aux11) + aux11;
1515 *var = cw[1] * (aux00 - aux11) + aux11;
1516}
int np
Number of pressure levels.
Definition: mptrac.h:3353
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3365
Here is the call graph for this function:

◆ intpol_met_space_3d_ml()

void intpol_met_space_3d_ml ( const met_t met,
float  array[EX][EY][EP],
const double  p,
const double  lon,
const double  lat,
double *  var 
)

Interpolates a meteorological variable in 3D space (longitude, latitude, pressure).

This function performs trilinear interpolation of a meteorological variable based on the provided longitude, latitude, and pressure coordinates. The meteorological data is given in a 3D array, and the function calculates the interpolated value and stores it in the variable pointed to by var. The function operates on model level data.

Parameters
[in]metPointer to a met_t structure containing the meteorological data.
[in]array3D array of meteorological data with dimensions [EX][EY][EP].
[in]pPressure coordinate at which to interpolate.
[in]lonLongitude coordinate at which to interpolate.
[in]latLatitude coordinate at which to interpolate.
[out]varPointer to a double where the interpolated value will be stored.
Author
Lars Hoffmann

Definition at line 1520 of file mptrac.c.

1526 {
1527
1528 /* Check longitude... */
1529 double lon2 = FMOD(lon, 360.);
1530 if (lon2 < met->lon[0])
1531 lon2 += 360;
1532 else if (lon2 > met->lon[met->nx - 1])
1533 lon2 -= 360;
1534
1535 /* Get horizontal indices... */
1536 int ix = locate_reg(met->lon, met->nx, lon2);
1537 int iy = locate_reg(met->lat, met->ny, lat);
1538
1539 /* Interpolate vertically... */
1540 int iz = locate_irr_float(met->pl[ix][iy], met->npl, p, 0);
1541 double aux00;
1542 if (p >= met->pl[ix][iy][iz + 1])
1543 aux00 = array[ix][iy][iz + 1];
1544 else if (p <= met->pl[ix][iy][iz])
1545 aux00 = array[ix][iy][iz];
1546 else
1547 aux00 = LIN(met->pl[ix][iy][iz],
1548 array[ix][iy][iz],
1549 met->pl[ix][iy][iz + 1], array[ix][iy][iz + 1], p);
1550
1551 iz = locate_irr_float(met->pl[ix][iy + 1], met->npl, p, iz);
1552 double aux01;
1553 if (p >= met->pl[ix][iy + 1][iz + 1])
1554 aux01 = array[ix][iy + 1][iz + 1];
1555 else if (p <= met->pl[ix][iy + 1][iz])
1556 aux01 = array[ix][iy + 1][iz];
1557 else
1558 aux01 = LIN(met->pl[ix][iy + 1][iz],
1559 array[ix][iy + 1][iz],
1560 met->pl[ix][iy + 1][iz + 1], array[ix][iy + 1][iz + 1], p);
1561
1562 iz = locate_irr_float(met->pl[ix + 1][iy], met->npl, p, iz);
1563 double aux10;
1564 if (p >= met->pl[ix + 1][iy][iz + 1])
1565 aux10 = array[ix + 1][iy][iz + 1];
1566 else if (p <= met->pl[ix + 1][iy][iz])
1567 aux10 = array[ix + 1][iy][iz];
1568 else
1569 aux10 = LIN(met->pl[ix + 1][iy][iz],
1570 array[ix + 1][iy][iz],
1571 met->pl[ix + 1][iy][iz + 1], array[ix + 1][iy][iz + 1], p);
1572
1573 iz = locate_irr_float(met->pl[ix + 1][iy + 1], met->npl, p, iz);
1574 double aux11;
1575 if (p >= met->pl[ix + 1][iy + 1][iz + 1])
1576 aux11 = array[ix + 1][iy + 1][iz + 1];
1577 else if (p <= met->pl[ix + 1][iy + 1][iz])
1578 aux11 = array[ix + 1][iy + 1][iz];
1579 else
1580 aux11 = LIN(met->pl[ix + 1][iy + 1][iz],
1581 array[ix + 1][iy + 1][iz],
1582 met->pl[ix + 1][iy + 1][iz + 1],
1583 array[ix + 1][iy + 1][iz + 1], p);
1584
1585 /* Interpolate horizontally... */
1586 double aux0 = LIN(met->lat[iy], aux00, met->lat[iy + 1], aux01, lat);
1587 double aux1 = LIN(met->lat[iy], aux10, met->lat[iy + 1], aux11, lat);
1588 *var = LIN(met->lon[ix], aux0, met->lon[ix + 1], aux1, lon2);
1589}
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:2146
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3473
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 1593 of file mptrac.c.

1601 {
1602
1603 /* Initialize interpolation... */
1604 if (init) {
1605
1606 /* Check longitude... */
1607 double lon2 = FMOD(lon, 360.);
1608 if (lon2 < met->lon[0])
1609 lon2 += 360;
1610 else if (lon2 > met->lon[met->nx - 1])
1611 lon2 -= 360;
1612
1613 /* Get interpolation indices... */
1614 ci[1] = locate_reg(met->lon, met->nx, lon2);
1615 ci[2] = locate_reg(met->lat, met->ny, lat);
1616
1617 /* Get interpolation weights... */
1618 cw[1] = (met->lon[ci[1] + 1] - lon2)
1619 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1620 cw[2] = (met->lat[ci[2] + 1] - lat)
1621 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1622 }
1623
1624 /* Set variables... */
1625 double aux00 = array[ci[1]][ci[2]];
1626 double aux01 = array[ci[1]][ci[2] + 1];
1627 double aux10 = array[ci[1] + 1][ci[2]];
1628 double aux11 = array[ci[1] + 1][ci[2] + 1];
1629
1630 /* Interpolate horizontally... */
1631 if (isfinite(aux00) && isfinite(aux01)
1632 && isfinite(aux10) && isfinite(aux11)) {
1633 aux00 = cw[2] * (aux00 - aux01) + aux01;
1634 aux11 = cw[2] * (aux10 - aux11) + aux11;
1635 *var = cw[1] * (aux00 - aux11) + aux11;
1636 } else {
1637 if (cw[2] < 0.5) {
1638 if (cw[1] < 0.5)
1639 *var = aux11;
1640 else
1641 *var = aux01;
1642 } else {
1643 if (cw[1] < 0.5)
1644 *var = aux10;
1645 else
1646 *var = aux00;
1647 }
1648 }
1649}
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 1653 of file mptrac.c.

1665 {
1666
1667 double var0, var1;
1668
1669 /* Spatial interpolation... */
1670 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
1671 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
1672
1673 /* Get weighting factor... */
1674 const double wt = (met1->time - ts) / (met1->time - met0->time);
1675
1676 /* Interpolate... */
1677 *var = wt * (var0 - var1) + var1;
1678}
Here is the call graph for this function:

◆ intpol_met_time_3d_ml()

void intpol_met_time_3d_ml ( 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 
)

Interpolates a meteorological variable in time and 3D space (longitude, latitude, pressure).

This function performs spatiotemporal interpolation of a meteorological variable based on the provided longitude, latitude, pressure, and timestamp. The meteorological data is given in two 3D arrays corresponding to two different time steps, and the function calculates the interpolated value and stores it in the variable pointed to by var. The function operates on model level data.

Parameters
[in]met0Pointer to a met_t structure containing the meteorological data for the first time step.
[in]array03D array of meteorological data for the first time step with dimensions [EX][EY][EP].
[in]met1Pointer to a met_t structure containing the meteorological data for the second time step.
[in]array13D array of meteorological data for the second time step with dimensions [EX][EY][EP].
[in]tsTimestamp at which to interpolate.
[in]pPressure coordinate at which to interpolate.
[in]lonLongitude coordinate at which to interpolate.
[in]latLatitude coordinate at which to interpolate.
[out]varPointer to a double where the interpolated value will be stored.
Author
Lars Hoffmann

Definition at line 1682 of file mptrac.c.

1691 {
1692
1693 double var0, var1;
1694
1695 /* Spatial interpolation... */
1696 intpol_met_space_3d_ml(met0, array0, p, lon, lat, &var0);
1697 intpol_met_space_3d_ml(met1, array1, p, lon, lat, &var1);
1698
1699 /* Interpolate... */
1700 *var = LIN(met0->time, var0, met1->time, var1, ts);
1701}
void intpol_met_space_3d_ml(const met_t *met, float array[EX][EY][EP], const double p, const double lon, const double lat, double *var)
Interpolates a meteorological variable in 3D space (longitude, latitude, pressure).
Definition: mptrac.c:1520
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 1705 of file mptrac.c.

1716 {
1717
1718 double var0, var1;
1719
1720 /* Spatial interpolation... */
1721 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
1722 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
1723
1724 /* Get weighting factor... */
1725 const double wt = (met1->time - ts) / (met1->time - met0->time);
1726
1727 /* Interpolate... */
1728 if (isfinite(var0) && isfinite(var1))
1729 *var = wt * (var0 - var1) + var1;
1730 else if (wt < 0.5)
1731 *var = var1;
1732 else
1733 *var = var0;
1734}
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 1738 of file mptrac.c.

1752 {
1753
1754 double aux0, aux1, aux00, aux01, aux10, aux11, mean = 0;
1755
1756 int n = 0;
1757
1758 /* Check longitude... */
1759 double lon2 = FMOD(lon, 360.);
1760 if (lon2 < lons[0])
1761 lon2 += 360;
1762 else if (lon2 > lons[nlon - 1])
1763 lon2 -= 360;
1764
1765 /* Get indices... */
1766 const int ix = locate_reg(lons, (int) nlon, lon2);
1767 const int iy = locate_reg(lats, (int) nlat, lat);
1768
1769 /* Calculate standard deviation... */
1770 *sigma = 0;
1771 for (int dx = 0; dx < 2; dx++)
1772 for (int dy = 0; dy < 2; dy++) {
1773 if (isfinite(array0[ix + dx][iy + dy])) {
1774 mean += array0[ix + dx][iy + dy];
1775 *sigma += SQR(array0[ix + dx][iy + dy]);
1776 n++;
1777 }
1778 if (isfinite(array1[ix + dx][iy + dy])) {
1779 mean += array1[ix + dx][iy + dy];
1780 *sigma += SQR(array1[ix + dx][iy + dy]);
1781 n++;
1782 }
1783 }
1784 if (n > 0)
1785 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
1786
1787 /* Linear interpolation... */
1788 if (method == 1 && isfinite(array0[ix][iy])
1789 && isfinite(array0[ix][iy + 1])
1790 && isfinite(array0[ix + 1][iy])
1791 && isfinite(array0[ix + 1][iy + 1])
1792 && isfinite(array1[ix][iy])
1793 && isfinite(array1[ix][iy + 1])
1794 && isfinite(array1[ix + 1][iy])
1795 && isfinite(array1[ix + 1][iy + 1])) {
1796
1797 aux00 = LIN(lons[ix], array0[ix][iy],
1798 lons[ix + 1], array0[ix + 1][iy], lon2);
1799 aux01 = LIN(lons[ix], array0[ix][iy + 1],
1800 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1801 aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat);
1802
1803 aux10 = LIN(lons[ix], array1[ix][iy],
1804 lons[ix + 1], array1[ix + 1][iy], lon2);
1805 aux11 = LIN(lons[ix], array1[ix][iy + 1],
1806 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1807 aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat);
1808
1809 *var = LIN(time0, aux0, time1, aux1, time);
1810 }
1811
1812 /* Nearest neighbor interpolation... */
1813 else {
1814 aux00 = NN(lons[ix], array0[ix][iy],
1815 lons[ix + 1], array0[ix + 1][iy], lon2);
1816 aux01 = NN(lons[ix], array0[ix][iy + 1],
1817 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1818 aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat);
1819
1820 aux10 = NN(lons[ix], array1[ix][iy],
1821 lons[ix + 1], array1[ix + 1][iy], lon2);
1822 aux11 = NN(lons[ix], array1[ix][iy + 1],
1823 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1824 aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat);
1825
1826 *var = NN(time0, aux0, time1, aux1, time);
1827 }
1828}
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1217
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1542
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 1832 of file mptrac.c.

1840 {
1841
1842 struct tm t0, *t1;
1843
1844 t0.tm_year = 100;
1845 t0.tm_mon = 0;
1846 t0.tm_mday = 1;
1847 t0.tm_hour = 0;
1848 t0.tm_min = 0;
1849 t0.tm_sec = 0;
1850
1851 const time_t jsec0 = (time_t) jsec + timegm(&t0);
1852 t1 = gmtime(&jsec0);
1853
1854 *year = t1->tm_year + 1900;
1855 *mon = t1->tm_mon + 1;
1856 *day = t1->tm_mday;
1857 *hour = t1->tm_hour;
1858 *min = t1->tm_min;
1859 *sec = t1->tm_sec;
1860 *remain = jsec - floor(jsec);
1861}

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

1869 {
1870
1871 /* Check number of data points... */
1872 if (nk < 2)
1873 return 1.0;
1874
1875 /* Get altitude... */
1876 const double z = Z(p);
1877
1878 /* Get weighting factor... */
1879 if (z < kz[0])
1880 return kw[0];
1881 else if (z > kz[nk - 1])
1882 return kw[nk - 1];
1883 else {
1884 int idx = locate_irr(kz, nk, z);
1885 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
1886 }
1887}
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 1891 of file mptrac.c.

1893 {
1894
1895 /*
1896 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
1897 and water vapor volume mixing ratio [1].
1898
1899 Reference: https://en.wikipedia.org/wiki/Lapse_rate
1900 */
1901
1902 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
1903
1904 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
1905}
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:212
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1529
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:182
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:172
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:167
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:162

◆ level_definitions()

void level_definitions ( ctl_t ctl)

Defines pressure levels for meteorological data.

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

Parameters
ctlControl structure containing information about pressure level definitions.

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

Note
Valid values for press_level_def are:
  • 0: Define 138 pressure levels.
  • 1: Define 92 pressure levels.
  • 2: Define 60 pressure levels.
  • 3: Define 147 pressure levels.
  • 4: Define 101 pressure levels.
  • 5: Define 62 pressure levels.
  • 6: Define 137 pressure levels.
  • 7: Define 59 pressure levels. Any other value for press_level_def will result in an error message.
Author
Jan Clemens

Definition at line 1909 of file mptrac.c.

1910 {
1911
1912
1913 if (0 == ctl->met_press_level_def) {
1914
1915 ctl->met_np = 138;
1916
1917 const double press[138] = {
1918 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1919 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1920 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1921 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1922 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1923 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1924 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1925 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1926 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1927 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1928 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1929 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1930 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1931 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1932 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1933 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1934 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1935 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1936 1010.8487, 1013.2500, 1044.45
1937 };
1938
1939 for (int ip = 0; ip < ctl->met_np; ip++)
1940 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1941
1942 } else if (1 == ctl->met_press_level_def) {
1943
1944 ctl->met_np = 92;
1945
1946 const double press[92] = {
1947 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1948 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1949 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1950 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1951 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1952 113.6382,
1953 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1954 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1955 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1956 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1957 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1958 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1959 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1960 1007.4431, 1010.8487, 1013.2500, 1044.45
1961 };
1962
1963 for (int ip = 0; ip < ctl->met_np; ip++)
1964 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1965
1966 } else if (2 == ctl->met_press_level_def) {
1967
1968 ctl->met_np = 60;
1969
1970 const double press[60] = {
1971 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1972 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1973 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1974 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1975 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1976 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1977 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1978 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
1979 };
1980
1981 for (int ip = 0; ip < ctl->met_np; ip++)
1982 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1983
1984 } else if (3 == ctl->met_press_level_def) {
1985
1986 ctl->met_np = 147;
1987
1988 const double press[147] = {
1989 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1990 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1991 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1992 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1993 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1994 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1995 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1996 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1997 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1998 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1999 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
2000 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
2001 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2002 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2003 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2004 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2005 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2006 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2007 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
2008 1031.97,
2009 1035.09, 1038.21, 1041.33, 1044.45
2010 };
2011
2012 for (int ip = 0; ip < ctl->met_np; ip++)
2013 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2014
2015 } else if (4 == ctl->met_press_level_def) {
2016
2017 ctl->met_np = 101;
2018
2019 const double press[101] = {
2020 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2021 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2022 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2023 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2024 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2025 113.6382,
2026 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2027 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2028 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2029 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2030 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2031 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2032 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2033 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
2034 1028.85, 1031.97,
2035 1035.09, 1038.21, 1041.33, 1044.45
2036 };
2037
2038 for (int ip = 0; ip < ctl->met_np; ip++)
2039 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2040
2041 } else if (5 == ctl->met_press_level_def) {
2042
2043 ctl->met_np = 62;
2044
2045 const double press[62] = {
2046 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2047 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2048 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2049 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2050 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2051 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2052 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2053 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
2054 1044.45
2055 };
2056
2057 for (int ip = 0; ip < ctl->met_np; ip++)
2058 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2059
2060 } else if (6 == ctl->met_press_level_def) {
2061
2062 ctl->met_np = 137;
2063
2064 const double press[137] = {
2065 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
2066 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
2067 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
2068 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
2069 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
2070 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2071 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
2072 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
2073 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
2074 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
2075 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
2076 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
2077 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
2078 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
2079 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
2080 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
2081 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
2082 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
2083 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
2084 1030.06, 1037.25, 1044.45
2085 };
2086
2087 for (int ip = 0; ip < ctl->met_np; ip++)
2088 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2089
2090 } else if (7 == ctl->met_press_level_def) {
2091
2092 ctl->met_np = 59;
2093
2094 const double press[59] = {
2095 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2096 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2097 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2098 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2099 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2100 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2101 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2102 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2103 1028.53, 1046.13
2104 };
2105
2106 for (int ip = 0; ip < ctl->met_np; ip++)
2107 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2108
2109 } else {
2110 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.")
2111 }
2112}
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2164
int met_np
Number of target pressure levels.
Definition: mptrac.h:2573
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2576

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

2119 {
2120
2121 int ilo = 0;
2122 int ihi = n - 1;
2123 int i = (ihi + ilo) >> 1;
2124
2125 if (xx[i] < xx[i + 1])
2126 while (ihi > ilo + 1) {
2127 i = (ihi + ilo) >> 1;
2128 if (xx[i] > x)
2129 ihi = i;
2130 else
2131 ilo = i;
2132 } else
2133 while (ihi > ilo + 1) {
2134 i = (ihi + ilo) >> 1;
2135 if (xx[i] <= x)
2136 ihi = i;
2137 else
2138 ilo = i;
2139 }
2140
2141 return ilo;
2142}

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

2150 {
2151
2152 int ilo = 0;
2153 int ihi = n - 1;
2154 int i = (ihi + ilo) >> 1;
2155
2156 if (x >= xx[ig] && x < xx[ig + 1])
2157 return ig;
2158
2159 if (xx[i] < xx[i + 1])
2160 while (ihi > ilo + 1) {
2161 i = (ihi + ilo) >> 1;
2162 if (xx[i] > x)
2163 ihi = i;
2164 else
2165 ilo = i;
2166 } else
2167 while (ihi > ilo + 1) {
2168 i = (ihi + ilo) >> 1;
2169 if (xx[i] <= x)
2170 ihi = i;
2171 else
2172 ilo = i;
2173 }
2174
2175 return ilo;
2176}

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

2183 {
2184
2185 /* Calculate index... */
2186 int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2187
2188 /* Check range... */
2189 if (i < 0)
2190 return 0;
2191 else if (i > n - 2)
2192 return n - 2;
2193 else
2194 return i;
2195}

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

2205 {
2206
2207 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2208 np, height_ap, 0);
2209 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2210 np, height_ap, ind[0]);
2211 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2212 np, height_ap, ind[1]);
2213 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2214 np, height_ap, ind[2]);
2215}
Here is the call graph for this function:

◆ module_advect()

void module_advect ( const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt 
)

Performs the advection of atmospheric particles using meteorological data.

This function advects particles in the atmosphere using meteorological data from two time steps, updating their positions and interpolating necessary data. It supports both pressure and zeta vertical coordinate systems.

Parameters
ctlPointer to the control structure containing configuration flags.
met0Pointer to the initial meteorological data structure.
met1Pointer to the final meteorological data structure.
atmPointer to the air parcel data structure.
dtArray of time step values for each particle.

The function performs the following operations:

  • Sets up a timer labeled "MODULE_ADVECTION" within the "PHYSICS" category for GPU profiling using NVTX.
  • Depending on the vertical coordinate system (pressure or zeta), it loops over each particle in the atmosphere (atm->np), initializing and updating their positions and velocities using meteorological data interpolation.

Pressure Coordinate System (ctl->vert_coord_ap == 0)

  • Initializes particle positions and velocities.
  • Performs integration over a specified number of nodes (ctl->advect) to update particle positions.
  • Interpolates meteorological data for velocity components (u, v, w).
  • Computes mean velocities and updates particle positions in longitude, latitude, and pressure.

Zeta Coordinate System (ctl->vert_coord_ap == 1)

  • Translates pressure into zeta coordinate if other modules have modified the pressure.
  • Initializes particle positions and velocities in zeta coordinates.
  • Performs integration over a specified number of nodes (ctl->advect) to update particle positions.
  • Interpolates meteorological data for velocity components (u, v) and zeta_dot.
  • Computes mean velocities and updates particle positions in longitude, latitude, and zeta.
  • Checks and corrects if zeta is below zero.
  • Translates updated zeta back into pressure coordinates.
Note
The function assumes that the atmospheric data structure (atm) contains arrays for time, longitude, latitude, and pressure for each point. The specific quantification of zeta is stored in atm->q[ctl.qnt_zeta].
Authors
Lars Hoffmann
Jan Clemens

Definition at line 2219 of file mptrac.c.

2224 {
2225
2226 /* Set timer... */
2227 SELECT_TIMER("MODULE_ADVECTION", "PHYSICS", NVTX_GPU);
2228
2229 /* Pressure coordinate... */
2230 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2231
2232 /* Loop over particles... */
2233 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
2234
2235 /* Init... */
2237 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2238 x[3] = { 0, 0, 0 };
2239
2240 /* Loop over integration nodes... */
2241 for (int i = 0; i < ctl->advect; i++) {
2242
2243 /* Set position... */
2244 if (i == 0) {
2245 dts = 0.0;
2246 x[0] = atm->lon[ip];
2247 x[1] = atm->lat[ip];
2248 x[2] = atm->p[ip];
2249 } else {
2250 dts = (i == 3 ? 1.0 : 0.5) * dt[ip];
2251 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2252 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2253 x[2] = atm->p[ip] + dts * w[i - 1];
2254 }
2255 double tm = atm->time[ip] + dts;
2256
2257 /* Interpolate meteo data on pressure levels... */
2258 if (ctl->advect_vert_coord == 0) {
2259 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2260 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2261 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2262 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2263 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2264 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2265 }
2266
2267 /* Interpolate meteo data on model levels... */
2268 else {
2269 intpol_met_time_3d_ml(met0, met0->ul, met1, met1->ul, tm, x[2],
2270 x[0], x[1], &u[i]);
2271 intpol_met_time_3d_ml(met0, met0->vl, met1, met1->vl, tm, x[2],
2272 x[0], x[1], &v[i]);
2273 intpol_met_time_3d_ml(met0, met0->wl, met1, met1->wl, tm, x[2],
2274 x[0], x[1], &w[i]);
2275 }
2276
2277 /* Get mean wind... */
2278 double k = 1.0;
2279 if (ctl->advect == 2)
2280 k = (i == 0 ? 0.0 : 1.0);
2281 else if (ctl->advect == 4)
2282 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2283 um += k * u[i];
2284 vm += k * v[i];
2285 wm += k * w[i];
2286 }
2287
2288 /* Set new position... */
2289 atm->time[ip] += dt[ip];
2290 atm->lon[ip] += DX2DEG(dt[ip] * um / 1000.,
2291 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2292 atm->lat[ip] += DY2DEG(dt[ip] * vm / 1000.);
2293 atm->p[ip] += dt[ip] * wm;
2294 }
2295 }
2296
2297 /* Zeta coordinate... */
2298 else if (ctl->advect_vert_coord == 1) {
2299
2300 /* Loop over particles... */
2301 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
2302
2303 /* If other modules have changed p translate it into a zeta... */
2304 if (ctl->advect_cpl_zeta_and_press_modules > 0) {
2306 intpol_met_4d_coord(met0, met0->pl, met0->zetal, met1,
2307 met1->pl, met1->zetal, atm->time[ip], atm->p[ip],
2308 atm->lon[ip], atm->lat[ip],
2309 &atm->q[ctl->qnt_zeta][ip], ci, cw, 1);
2310 }
2311
2312 /* Init... */
2313 double dts, u[4], um = 0, v[4], vm = 0, zeta_dot[4], zeta_dotm = 0,
2314 x[3] = { 0, 0, 0 };
2315
2316 /* Loop over integration nodes... */
2317 for (int i = 0; i < ctl->advect; i++) {
2318
2319 /* Set position... */
2320 if (i == 0) {
2321 dts = 0.0;
2322 x[0] = atm->lon[ip];
2323 x[1] = atm->lat[ip];
2324 x[2] = atm->q[ctl->qnt_zeta][ip];
2325 } else {
2326 dts = (i == 3 ? 1.0 : 0.5) * dt[ip];
2327 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2328 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2329 x[2] = atm->q[ctl->qnt_zeta][ip] + dts * zeta_dot[i - 1];
2330 }
2331 double tm = atm->time[ip] + dts;
2332
2333 /* Interpolate meteo data... */
2335 intpol_met_4d_coord(met0, met0->zetal, met0->ul, met1, met1->zetal,
2336 met1->ul, tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2337 intpol_met_4d_coord(met0, met0->zetal, met0->vl, met1, met0->zetal,
2338 met1->vl, tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2339 intpol_met_4d_coord(met0, met0->zetal, met0->zeta_dotl, met1,
2340 met1->zetal, met1->zeta_dotl, tm, x[2], x[0],
2341 x[1], &zeta_dot[i], ci, cw, 0);
2342
2343 /* Get mean wind... */
2344 double k = 1.0;
2345 if (ctl->advect == 2)
2346 k = (i == 0 ? 0.0 : 1.0);
2347 else if (ctl->advect == 4)
2348 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2349 um += k * u[i];
2350 vm += k * v[i];
2351 zeta_dotm += k * zeta_dot[i];
2352 }
2353
2354 /* Set new position... */
2355 atm->time[ip] += dt[ip];
2356 atm->lon[ip] += DX2DEG(dt[ip] * um / 1000.,
2357 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2358 atm->lat[ip] += DY2DEG(dt[ip] * vm / 1000.);
2359 atm->q[ctl->qnt_zeta][ip] += dt[ip] * zeta_dotm;
2360
2361 /* Check if zeta is below zero... */
2362 if (atm->q[ctl->qnt_zeta][ip] < 0) {
2363 atm->q[ctl->qnt_zeta][ip] = 0;
2364 }
2365
2366 /* Set new position also in pressure coordinates... */
2368 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2369 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2370 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2371 }
2372 }
2373}
void intpol_met_time_3d_ml(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)
Interpolates a meteorological variable in time and 3D space (longitude, latitude, pressure).
Definition: mptrac.c:1682
void intpol_met_4d_coord(const met_t *met0, float heights0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float heights1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double height, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological variables to a given position and time.
Definition: mptrac.c:1282
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:1653
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1259
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:521
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:539
double time[NP]
Time [s].
Definition: mptrac.h:3126
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3135
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3132
int np
Number of air parcels.
Definition: mptrac.h:3123
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3138
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3129
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2636
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2378
int advect_cpl_zeta_and_press_modules
Coupled use of pressure based modules and diabatic advection.
Definition: mptrac.h:2161
int advect_vert_coord
Vertical coordinate of air parcels (0=pressure, 1=zeta, 2=eta).
Definition: mptrac.h:2167
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3488
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3446
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3482
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3479
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3440
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3476
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3443
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3485
Here is the call graph for this function:

◆ module_advect_init()

void module_advect_init ( const ctl_t ctl,
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.
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_ADVECTION" 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 2377 of file mptrac.c.

2381 {
2382
2383 /* Initialize pressure consistent with zeta... */
2384 if (ctl->advect_vert_coord == 1) {
2385#pragma omp parallel for default(shared)
2386 for (int ip = 0; ip < atm->np; ip++) {
2387
2388 /* Check time... */
2389 if (atm->time[ip] < met0->time || atm->time[ip] > met1->time)
2390 ERRMSG("Time of air parcel is out of range!");
2391
2392 /* Interpolate pressure... */
2394 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2395 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2396 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2397 }
2398 }
2399}
Here is the call graph for this function:

◆ module_bound_cond()

void module_bound_cond ( const ctl_t ctl,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt 
)

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.
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.
dtPointer to the time step value.
Authors
Lars Hoffmann
Mingzhao Liu

Definition at line 2403 of file mptrac.c.

2409 {
2410
2411 /* Set timer... */
2412 SELECT_TIMER("MODULE_BOUNDCOND", "PHYSICS", NVTX_GPU);
2413
2414 /* Check quantity flags... */
2415 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2416 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2417 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2418 return;
2419
2420 /* Loop over particles... */
2421 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,met0,met1,atm,dt)") {
2422
2423 /* Check latitude and pressure range... */
2424 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2425 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2426 continue;
2427
2428 /* Check surface layer... */
2429 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2430 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2431
2432 /* Get surface pressure... */
2433 double ps;
2435 INTPOL_2D(ps, 1);
2436
2437 /* Check pressure... */
2438 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2439 continue;
2440
2441 /* Check height... */
2442 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2443 continue;
2444
2445 /* Check zeta range... */
2446 if (ctl->bound_zetas > 0) {
2447 double t;
2448 INTPOL_3D(t, 1);
2449 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2450 continue;
2451 }
2452
2453 /* Check planetary boundary layer... */
2454 if (ctl->bound_pbl) {
2455 double pbl;
2456 INTPOL_2D(pbl, 0);
2457 if (atm->p[ip] < pbl)
2458 continue;
2459 }
2460 }
2461
2462 /* Set mass and volume mixing ratio... */
2463 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2464 atm->q[ctl->qnt_m][ip] =
2465 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2466 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2467 atm->q[ctl->qnt_vmr][ip] =
2468 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2469
2470 /* Set CFC-10 volume mixing ratio... */
2471 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2472 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2473
2474 /* Set CFC-11 volume mixing ratio... */
2475 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2476 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2477
2478 /* Set CFC-12 volume mixing ratio... */
2479 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2480 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2481
2482 /* Set N2O volume mixing ratio... */
2483 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2484 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2485
2486 /* Set SF6 volume mixing ratio... */
2487 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2488 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2489
2490 /* Set age of air... */
2491 if (ctl->qnt_aoa >= 0)
2492 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2493 }
2494}
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:383
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:707
#define ZETA(ps, p, t)
Calculate potential vorticity using the Zeta approximation.
Definition: mptrac.h:1788
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:690
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3324
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3330
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3318
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3321
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3327
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2447
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2204
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2456
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2756
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2705
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2441
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2678
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2207
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2693
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2711
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2699
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2684
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2690
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2687
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2450
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2444
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2453
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2702
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2681
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2696
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2747
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2759
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2750
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2753
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2708
Here is the call graph for this function:

◆ module_chemgrid()

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

Calculate grid data for chemistry modules.

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

Parameters
ctlPointer to the control structure containing simulation parameters.
climPointer to the climate data structure containing climatological data.
met0Pointer to the first meteorological data structure.
met1Pointer to the second meteorological data structure.
atmPointer to the atmospheric data structure containing particle information.
tTime for which chemical grid is updated.
Authors
Mingzhao Liu
Lars Hoffmann

Definition at line 2498 of file mptrac.c.

2503 {
2504
2505 /* Check quantities... */
2506 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
2507 return;
2508 if (ctl->molmass <= 0)
2509 ERRMSG("Molar mass is not defined!");
2510
2511 /* Set timer... */
2512 SELECT_TIMER("MODULE_CHEMGRID", "PHYSICS", NVTX_GPU);
2513
2514 /* Allocate... */
2515 const int np = atm->np;
2516 const int nz = ctl->chemgrid_nz;
2517 const int nx = ctl->chemgrid_nx;
2518 const int ny = ctl->chemgrid_ny;
2519 const int ngrid = nx * ny * nz;
2520
2521 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2522 double *restrict const press =
2523 (double *) malloc((size_t) nz * sizeof(double));
2524 double *restrict const mass =
2525 (double *) calloc((size_t) ngrid, sizeof(double));
2526 double *restrict const area =
2527 (double *) malloc((size_t) ny * sizeof(double));
2528 double *restrict const lon =
2529 (double *) malloc((size_t) nx * sizeof(double));
2530 double *restrict const lat =
2531 (double *) malloc((size_t) ny * sizeof(double));
2532
2533 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2534 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2535 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2536
2537 /* Set grid box size... */
2538 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2539 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2540 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2541
2542 /* Set vertical coordinates... */
2543#ifdef _OPENACC
2544#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np],z[0:nz],press[0:nz],mass[0:ngrid],area[0:ny],lon[0:nx],lat[0:ny])
2545#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2546#pragma acc parallel loop independent gang vector
2547#else
2548#pragma omp parallel for default(shared)
2549#endif
2550 for (int iz = 0; iz < nz; iz++) {
2551 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2552 press[iz] = P(z[iz]);
2553 }
2554
2555 /* Set time interval for output... */
2556 const double t0 = tt - 0.5 * ctl->dt_mod;
2557 const double t1 = tt + 0.5 * ctl->dt_mod;
2558
2559 /* Get indices... */
2560#ifdef _OPENACC
2561#pragma acc parallel loop independent gang vector
2562#else
2563#pragma omp parallel for default(shared)
2564#endif
2565 for (int ip = 0; ip < np; ip++) {
2566 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2567 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2568 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2569 if (atm->time[ip] < t0 || atm->time[ip] > t1
2570 || ixs[ip] < 0 || ixs[ip] >= nx
2571 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2572 izs[ip] = -1;
2573 }
2574
2575 /* Set horizontal coordinates... */
2576#ifdef _OPENACC
2577#pragma acc parallel loop independent gang vector
2578#else
2579#pragma omp parallel for default(shared)
2580#endif
2581 for (int ix = 0; ix < nx; ix++)
2582 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
2583#ifdef _OPENACC
2584#pragma acc parallel loop independent gang vector
2585#else
2586#pragma omp parallel for default(shared)
2587#endif
2588 for (int iy = 0; iy < ny; iy++) {
2589 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
2590 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
2591 }
2592
2593 /* Get mass per grid box... */
2594#ifdef _OPENACC
2595#pragma acc parallel loop independent gang vector
2596#endif
2597 for (int ip = 0; ip < np; ip++)
2598 if (izs[ip] >= 0)
2599#ifdef _OPENACC
2600#pragma acc atomic update
2601#endif
2602 mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)]
2603 += atm->q[ctl->qnt_m][ip];
2604
2605 /* Assign grid data to air parcels ... */
2606#ifdef _OPENACC
2607#pragma acc parallel loop independent gang vector
2608#else
2609#pragma omp parallel for default(shared)
2610#endif
2611 for (int ip = 0; ip < np; ip++)
2612 if (izs[ip] >= 0) {
2613
2614 /* Interpolate temperature... */
2615 double temp;
2617 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt, press[izs[ip]],
2618 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
2619
2620 /* Set mass... */
2621 double m = mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)];
2622
2623 /* Calculate volume mixing ratio... */
2624 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
2625 / (1e9 * RHO(press[izs[ip]], temp) * area[iys[ip]] * dz);
2626 }
2627#ifdef _OPENACC
2628#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
2629#endif
2630
2631 /* Free... */
2632 free(mass);
2633 free(lon);
2634 free(lat);
2635 free(area);
2636 free(z);
2637 free(press);
2638 free(ixs);
2639 free(iys);
2640 free(izs);
2641
2642}
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:389
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:192
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1289
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1466
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2717
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2804
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2801
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2819
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2822
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2810
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2813
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2468
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2798
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2807
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2816
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2411
Here is the call graph for this function:

◆ module_chem_init()

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

Initializes the chemistry modules by setting atmospheric composition.

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

Parameters
ctlPointer to the control structure containing quantity flags.
climPointer to the climatology structure containing climatological data.
met0Pointer to the initial meteorological data structure.
met1Pointer to the final meteorological data structure.
atmPointer to the air parcel data structure.

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

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

Definition at line 2646 of file mptrac.c.

2651 {
2652
2653#pragma omp parallel for default(shared)
2654 for (int ip = 0; ip < atm->np; ip++) {
2655
2656 /* Check time... */
2657 if (atm->time[ip] < met0->time || atm->time[ip] > met1->time)
2658 ERRMSG("Time of air parcel is out of range!");
2659
2660 /* Set H2O and O3 using meteo data... */
2662 if (ctl->qnt_Ch2o >= 0) {
2663 double h2o;
2664 INTPOL_3D(h2o, 1);
2665 SET_ATM(qnt_Ch2o, h2o);
2666 }
2667 if (ctl->qnt_Co3 >= 0) {
2668 double o3;
2669 INTPOL_3D(o3, 1);
2670 SET_ATM(qnt_Co3, o3);
2671 }
2672
2673 /* Set radical species... */
2674 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
2675 atm->lon[ip], atm->lat[ip], atm->p[ip]));
2676 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
2677 atm->lat[ip], atm->p[ip]));
2678 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
2679 atm->lat[ip], atm->p[ip]));
2680 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
2681 atm->lat[ip], atm->p[ip]));
2682 }
2683}
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:1485
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3312
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3315
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3309
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2414
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2417
Here is the call graph for this function:

◆ module_convection()

void module_convection ( const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt,
double *  rs 
)

Simulate convective processes for atmospheric particles.

This function simulates convective processes for atmospheric particles based on convective available potential energy (CAPE) and convective inhibition (CIN). It loops over each particle and checks whether the CAPE exceeds a specified threshold. If CAPE is above the threshold and meets the conditions, it performs convective mixing to update the particle's pressure based on random numbers generated for each particle.

The function interpolates CAPE and CIN from meteorological data and checks whether the particle is above the cloud top level. If the conditions are met, it determines the pressure range for vertical mixing and calculates the density range based on temperature at different pressure levels. It then calculates the new density based on random numbers and updates the particle's pressure accordingly.

Parameters
ctlPointer to the control structure containing simulation parameters.
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.
dtPointer to the time step value.
rsPointer to an array of random numbers generated for each particle.
Author
Lars Hoffmann

Definition at line 2687 of file mptrac.c.

2693 {
2694
2695 /* Set timer... */
2696 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
2697
2698 /* Create random numbers... */
2699 module_rng(ctl, rs, (size_t) atm->np, 0);
2700
2701 /* Loop over particles... */
2702 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt,rs)") {
2703
2704 /* Interpolate CAPE... */
2705 double cape;
2707 INTPOL_2D(cape, 1);
2708
2709 /* Check threshold... */
2710 if (isfinite(cape) && cape >= ctl->conv_cape) {
2711
2712 /* Check CIN... */
2713 if (ctl->conv_cin > 0) {
2714 double cin;
2715 INTPOL_2D(cin, 0);
2716 if (isfinite(cin) && cin >= ctl->conv_cin)
2717 continue;
2718 }
2719
2720 /* Interpolate equilibrium level... */
2721 double pel;
2722 INTPOL_2D(pel, 0);
2723
2724 /* Check whether particle is above cloud top... */
2725 if (!isfinite(pel) || atm->p[ip] < pel)
2726 continue;
2727
2728 /* Set pressure range for vertical mixing... */
2729 double pbot = atm->p[ip];
2730 double ptop = atm->p[ip];
2731 if (ctl->conv_mix_bot == 1) {
2732 double ps;
2733 INTPOL_2D(ps, 0);
2734 pbot = ps;
2735 }
2736 if (ctl->conv_mix_top == 1)
2737 ptop = pel;
2738
2739 /* Get density range... */
2740 double tbot, ttop;
2741 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2742 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
2743 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2744 ptop, atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
2745 double rhobot = pbot / tbot;
2746 double rhotop = ptop / ttop;
2747
2748 /* Get new density... */
2749 double rho = rhobot + (rhotop - rhobot) * rs[ip];
2750
2751 /* Get pressure... */
2752 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
2753 }
2754 }
2755}
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:3690
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2663
int conv_mix_bot
Lower level for mixing (0=particle pressure, 1=surface).
Definition: mptrac.h:2672
int conv_mix_top
Upper level for mixing (0=particle pressure, 1=EL).
Definition: mptrac.h:2675
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2666
Here is the call graph for this function:

◆ module_decay()

void module_decay ( const ctl_t ctl,
const clim_t clim,
atm_t atm,
const double *  dt 
)

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.
climPointer to the climate data structure containing atmospheric data.
atmPointer to the atmospheric data structure containing particle information.
dtPointer to the time step value.
Author
Lars Hoffmann

Definition at line 2759 of file mptrac.c.

2763 {
2764
2765 /* Set timer... */
2766 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
2767
2768 /* Check quantity flags... */
2769 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2770 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2771
2772 /* Loop over particles... */
2773 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,atm,dt)") {
2774
2775 /* Get weighting factor... */
2776 const double w =
2777 tropo_weight(clim, atm->time[ip], atm->lat[ip], atm->p[ip]);
2778
2779 /* Set lifetime... */
2780 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
2781
2782 /* Calculate exponential decay... */
2783 const double aux = exp(-dt[ip] / tdec);
2784 if (ctl->qnt_m >= 0) {
2785 if (ctl->qnt_mloss_decay >= 0)
2786 atm->q[ctl->qnt_mloss_decay][ip]
2787 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2788 atm->q[ctl->qnt_m][ip] *= aux;
2789 if (ctl->qnt_loss_rate >= 0)
2790 atm->q[ctl->qnt_loss_rate][ip] += 1 / tdec;
2791 }
2792 if (ctl->qnt_vmr >= 0)
2793 atm->q[ctl->qnt_vmr][ip] *= aux;
2794 }
2795}
double tropo_weight(const clim_t *clim, const double t, const double lat, const double p)
Computes the weighting factor for a given pressure with respect to the tropopause.
Definition: mptrac.c:8448
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2354
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2351
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2723
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2720
Here is the call graph for this function:

◆ module_diffusion_meso()

void module_diffusion_meso ( const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
cache_t cache,
const double *  dt,
double *  rs 
)

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.
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 temporary storage.
dtPointer to the time step value.
rsPointer to the array of random numbers.
Author
Lars Hoffmann

Definition at line 2799 of file mptrac.c.

2806 {
2807
2808 /* Set timer... */
2809 SELECT_TIMER("MODULE_TURBMESO", "PHYSICS", NVTX_GPU);
2810
2811 /* Create random numbers... */
2812 module_rng(ctl, rs, 3 * (size_t) atm->np, 1);
2813
2814 /* Loop over particles... */
2815 PARTICLE_LOOP(0, atm->np, 1,
2816 "acc data present(ctl,met0,met1,atm,cache,dt,rs)") {
2817
2818 /* Get indices... */
2819 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
2820 const int iy = locate_reg(met0->lat, met0->ny, atm->lat[ip]);
2821 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
2822
2823 /* Get standard deviations of local wind data... */
2824 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
2825 for (int i = 0; i < 2; i++)
2826 for (int j = 0; j < 2; j++)
2827 for (int k = 0; k < 2; k++) {
2828 umean += met0->u[ix + i][iy + j][iz + k];
2829 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
2830 vmean += met0->v[ix + i][iy + j][iz + k];
2831 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
2832 wmean += met0->w[ix + i][iy + j][iz + k];
2833 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
2834
2835 umean += met1->u[ix + i][iy + j][iz + k];
2836 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
2837 vmean += met1->v[ix + i][iy + j][iz + k];
2838 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
2839 wmean += met1->w[ix + i][iy + j][iz + k];
2840 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
2841 }
2842 usig = usig / 16.f - SQR(umean / 16.f);
2843 usig = (usig > 0 ? sqrtf(usig) : 0);
2844 vsig = vsig / 16.f - SQR(vmean / 16.f);
2845 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
2846 wsig = wsig / 16.f - SQR(wmean / 16.f);
2847 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
2848
2849 /* Set temporal correlations for mesoscale fluctuations... */
2850 const double r = 1 - 2 * fabs(dt[ip]) / ctl->dt_met;
2851 const double r2 = sqrt(1 - r * r);
2852
2853 /* Calculate horizontal mesoscale wind fluctuations... */
2854 if (ctl->turb_mesox > 0) {
2855 cache->uvwp[ip][0] =
2856 (float) (r * cache->uvwp[ip][0] +
2857 r2 * rs[3 * ip] * ctl->turb_mesox * usig);
2858 atm->lon[ip] +=
2859 DX2DEG(cache->uvwp[ip][0] * dt[ip] / 1000., atm->lat[ip]);
2860
2861 cache->uvwp[ip][1] =
2862 (float) (r * cache->uvwp[ip][1] +
2863 r2 * rs[3 * ip + 1] * ctl->turb_mesox * vsig);
2864 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * dt[ip] / 1000.);
2865 }
2866
2867 /* Calculate vertical mesoscale wind fluctuations... */
2868 if (ctl->turb_mesoz > 0) {
2869 cache->uvwp[ip][2] =
2870 (float) (r * cache->uvwp[ip][2] +
2871 r2 * rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
2872 atm->p[ip] += cache->uvwp[ip][2] * dt[ip];
2873 }
2874 }
2875}
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3163
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2660
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2657
Here is the call graph for this function:

◆ module_diffusion_turb()

void module_diffusion_turb ( const ctl_t ctl,
const clim_t clim,
atm_t atm,
const double *  dt,
double *  rs 
)

Simulate turbulent diffusion for atmospheric particles.

This function simulates turbulent diffusion for atmospheric particles, including horizontal and vertical diffusion. It calculates diffusivity based on the provided weighting factor and turbulence parameters. The diffusion coefficients are then used to calculate horizontal and vertical displacements of particles based on the provided random numbers and time step.

The function loops over each particle and calculates the weighting factor based on the atmospheric properties. It then computes diffusivity for horizontal and vertical diffusion. Based on the diffusivity values and provided random numbers, it calculates horizontal and vertical displacements of particles and updates their positions accordingly.

Parameters
ctlPointer to the control structure containing simulation parameters.
climPointer to the climatological data structure containing atmospheric properties.
atmPointer to the atmospheric data structure containing particle information.
dtPointer to the time step value.
rsPointer to the array of random numbers.
Author
Lars Hoffmann

Definition at line 2879 of file mptrac.c.

2884 {
2885
2886 /* Set timer... */
2887 SELECT_TIMER("MODULE_TURBDIFF", "PHYSICS", NVTX_GPU);
2888
2889 /* Create random numbers... */
2890 module_rng(ctl, rs, 3 * (size_t) atm->np, 1);
2891
2892 /* Loop over particles... */
2893 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,atm,dt,rs)") {
2894
2895 /* Get weighting factor... */
2896 const double w =
2897 tropo_weight(clim, atm->time[ip], atm->lat[ip], atm->p[ip]);
2898
2899 /* Set diffusivity... */
2900 const double dx = w * ctl->turb_dx_trop + (1 - w) * ctl->turb_dx_strat;
2901 const double dz = w * ctl->turb_dz_trop + (1 - w) * ctl->turb_dz_strat;
2902
2903 /* Horizontal turbulent diffusion... */
2904 if (dx > 0) {
2905 const double sigma = sqrt(2.0 * dx * fabs(dt[ip]));
2906 atm->lon[ip] += DX2DEG(rs[3 * ip] * sigma / 1000., atm->lat[ip]);
2907 atm->lat[ip] += DY2DEG(rs[3 * ip + 1] * sigma / 1000.);
2908 }
2909
2910 /* Vertical turbulent diffusion... */
2911 if (dz > 0) {
2912 const double sigma = sqrt(2.0 * dz * fabs(dt[ip]));
2913 atm->p[ip] += DZ2DP(rs[3 * ip + 2] * sigma / 1000., atm->p[ip]);
2914 }
2915 }
2916}
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:556
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2651
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2648
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2645
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2654
Here is the call graph for this function:

◆ module_dry_deposition()

void module_dry_deposition ( const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt 
)

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.
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.
dtPointer to the time step value.
Author
Lars Hoffmann

Definition at line 2920 of file mptrac.c.

2925 {
2926
2927 /* Set timer... */
2928 SELECT_TIMER("MODULE_DRYDEPO", "PHYSICS", NVTX_GPU);
2929
2930 /* Check quantity flags... */
2931 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2932 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2933
2934 /* Loop over particles... */
2935 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
2936
2937 /* Get surface pressure... */
2938 double ps;
2940 INTPOL_2D(ps, 1);
2941
2942 /* Check whether particle is above the surface layer... */
2943 if (atm->p[ip] < ps - ctl->dry_depo_dp)
2944 continue;
2945
2946 /* Set depth of surface layer... */
2947 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
2948
2949 /* Calculate sedimentation velocity for particles... */
2950 double v_dep;
2951 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
2952
2953 /* Get temperature... */
2954 double t;
2955 INTPOL_3D(t, 1);
2956
2957 /* Set deposition velocity... */
2958 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
2959 atm->q[ctl->qnt_rhop][ip]);
2960 }
2961
2962 /* Use explicit sedimentation velocity for gases... */
2963 else
2964 v_dep = ctl->dry_depo_vdep;
2965
2966 /* Calculate loss of mass based on deposition velocity... */
2967 const double aux = exp(-dt[ip] * v_dep / dz);
2968 if (ctl->qnt_m >= 0) {
2969 if (ctl->qnt_mloss_dry >= 0)
2970 atm->q[ctl->qnt_mloss_dry][ip]
2971 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2972 atm->q[ctl->qnt_m][ip] *= aux;
2973 if (ctl->qnt_loss_rate >= 0)
2974 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
2975 }
2976 if (ctl->qnt_vmr >= 0)
2977 atm->q[ctl->qnt_vmr][ip] *= aux;
2978 }
2979}
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:8170
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2213
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2210
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2873
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2348
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2876
Here is the call graph for this function:

◆ module_h2o2_chem()

void module_h2o2_chem ( const ctl_t ctl,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt 
)

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.
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.
dtPointer to an array containing the time step for each particle.
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 2983 of file mptrac.c.

2989 {
2990
2991 /* Set timer... */
2992 SELECT_TIMER("MODULE_H2O2CHEM", "PHYSICS", NVTX_GPU);
2993
2994 /* Check quantity flags... */
2995 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2996 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2997
2998 /* Parameter of SO2 correction... */
2999 const double a = 3.12541941e-06;
3000 const double b = -5.72532259e-01;
3001 const double low = pow(1 / a, 1 / b);
3002
3003 /* Loop over particles... */
3004 PARTICLE_LOOP(0, atm->np, 1, "acc data present(clim,ctl,met0,met1,atm,dt)") {
3005
3006 /* Check whether particle is inside cloud... */
3007 double lwc, rwc;
3009 INTPOL_3D(lwc, 1);
3010 INTPOL_3D(rwc, 0);
3011 if (!(lwc > 0 || rwc > 0))
3012 continue;
3013
3014 /* Get temperature... */
3015 double t;
3016 INTPOL_3D(t, 0);
3017
3018 /* Get molecular density... */
3019 const double M = MOLEC_DENS(atm->p[ip], t);
3020
3021 /* Reaction rate (Berglen et al., 2004)... */
3022 const double k = 9.1e7 * exp(-29700 / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3023
3024 /* Henry constant of SO2... */
3025 const double H_SO2 = 1.3e-2 * exp(2900 * (1. / t - 1. / 298.15)) * RI * t;
3026 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3027
3028 /* Henry constant of H2O2... */
3029 const double H_h2o2 = 8.3e2 * exp(7600 * (1 / t - 1 / 298.15)) * RI * t;
3030
3031 /* Correction factor for high SO2 concentration
3032 (if qnt_Cx is defined, the correction is switched on)... */
3033 double cor = 1;
3034 if (ctl->qnt_Cx >= 0)
3035 cor = atm->q[ctl->qnt_Cx][ip] >
3036 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3037
3038 const double h2o2 = H_h2o2
3039 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3040 * M * cor * 1000 / AVO; /* unit: mol/L */
3041
3042 /* Volume water content in cloud [m^3 m^(-3)]... */
3043 const double rho_air = 100 * atm->p[ip] / (RI * t) * MA / 1000;
3044 const double CWC = (lwc + rwc) * rho_air / 1000;
3045
3046 /* Calculate exponential decay (Rolph et al., 1992)... */
3047 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3048 const double aux = exp(-dt[ip] * rate_coef);
3049 if (ctl->qnt_m >= 0) {
3050 if (ctl->qnt_mloss_h2o2 >= 0)
3051 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3052 atm->q[ctl->qnt_m][ip] *= aux;
3053 if (ctl->qnt_loss_rate >= 0)
3054 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3055 }
3056 if (ctl->qnt_vmr >= 0)
3057 atm->q[ctl->qnt_vmr][ip] *= aux;
3058 }
3059}
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:157
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:987
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:222
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2339
Here is the call graph for this function:

◆ module_isosurf_init()

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

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

3068 {
3069
3070 double t;
3071
3072 /* Set timer... */
3073 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3074
3075 /* Init... */
3077
3078 /* Save pressure... */
3079 if (ctl->isosurf == 1)
3080 for (int ip = 0; ip < atm->np; ip++)
3081 cache->iso_var[ip] = atm->p[ip];
3082
3083 /* Save density... */
3084 else if (ctl->isosurf == 2)
3085 for (int ip = 0; ip < atm->np; ip++) {
3086 INTPOL_3D(t, 1);
3087 cache->iso_var[ip] = atm->p[ip] / t;
3088 }
3089
3090 /* Save potential temperature... */
3091 else if (ctl->isosurf == 3)
3092 for (int ip = 0; ip < atm->np; ip++) {
3093 INTPOL_3D(t, 1);
3094 cache->iso_var[ip] = THETA(atm->p[ip], t);
3095 }
3096
3097 /* Read balloon pressure data... */
3098 else if (ctl->isosurf == 4) {
3099
3100 /* Write info... */
3101 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3102
3103 /* Open file... */
3104 FILE *in;
3105 if (!(in = fopen(ctl->balloon, "r")))
3106 ERRMSG("Cannot open file!");
3107
3108 /* Read pressure time series... */
3109 char line[LEN];
3110 while (fgets(line, LEN, in))
3111 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3112 &(cache->iso_ps[cache->iso_n])) == 2)
3113 if ((++cache->iso_n) > NP)
3114 ERRMSG("Too many data points!");
3115
3116 /* Check number of points... */
3117 if (cache->iso_n < 1)
3118 ERRMSG("Could not read any data!");
3119
3120 /* Close file... */
3121 fclose(in);
3122 }
3123}
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1629
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:241
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3157
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3160
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3154
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3151
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2633
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2630

◆ module_isosurf()

void module_isosurf ( const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
cache_t cache,
const double *  dt 
)

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.
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 containing initialized data.
dtArray of time step values for each particle.
Author
Lars Hoffmann

Definition at line 3127 of file mptrac.c.

3133 {
3134
3135 /* Set timer... */
3136 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3137
3138 /* Loop over particles... */
3139 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm,cache,dt)") {
3140
3141 /* Init... */
3142 double t;
3144
3145 /* Restore pressure... */
3146 if (ctl->isosurf == 1)
3147 atm->p[ip] = cache->iso_var[ip];
3148
3149 /* Restore density... */
3150 else if (ctl->isosurf == 2) {
3151 INTPOL_3D(t, 1);
3152 atm->p[ip] = cache->iso_var[ip] * t;
3153 }
3154
3155 /* Restore potential temperature... */
3156 else if (ctl->isosurf == 3) {
3157 INTPOL_3D(t, 1);
3158 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3159 }
3160
3161 /* Interpolate pressure... */
3162 else if (ctl->isosurf == 4) {
3163 if (atm->time[ip] <= cache->iso_ts[0])
3164 atm->p[ip] = cache->iso_ps[0];
3165 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3166 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3167 else {
3168 int idx = locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3169 atm->p[ip] = LIN(cache->iso_ts[idx], cache->iso_ps[idx],
3170 cache->iso_ts[idx + 1], cache->iso_ps[idx + 1],
3171 atm->time[ip]);
3172 }
3173 }
3174 }
3175}
Here is the call graph for this function:

◆ module_meteo()

void module_meteo ( const ctl_t ctl,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt 
)

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.
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.
dtArray of time step values for each particle.
Author
Lars Hoffmann

Definition at line 3232 of file mptrac.c.

3238 {
3239
3240 /* Set timer... */
3241 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
3242
3243 /* Check quantity flags... */
3244 if (ctl->qnt_tsts >= 0)
3245 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3246 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3247
3248 /* Loop over particles... */
3249 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,clim,met0,met1,atm,dt)") {
3250
3251 double ps, ts, zs, us, vs, lsm, sst, pbl, pt, pct, pcb, cl, plcl, plfc,
3252 pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot, o3,
3253 lwc, rwc, iwc, swc, cc, z, zt;
3254
3255 /* Interpolate meteo data... */
3257 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3258
3259 /* Set quantities... */
3260 SET_ATM(qnt_ps, ps);
3261 SET_ATM(qnt_ts, ts);
3262 SET_ATM(qnt_zs, zs);
3263 SET_ATM(qnt_us, us);
3264 SET_ATM(qnt_vs, vs);
3265 SET_ATM(qnt_lsm, lsm);
3266 SET_ATM(qnt_sst, sst);
3267 SET_ATM(qnt_pbl, pbl);
3268 SET_ATM(qnt_pt, pt);
3269 SET_ATM(qnt_tt, tt);
3270 SET_ATM(qnt_zt, zt);
3271 SET_ATM(qnt_h2ot, h2ot);
3272 SET_ATM(qnt_zg, z);
3273 SET_ATM(qnt_p, atm->p[ip]);
3274 SET_ATM(qnt_t, t);
3275 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3276 SET_ATM(qnt_u, u);
3277 SET_ATM(qnt_v, v);
3278 SET_ATM(qnt_w, w);
3279 SET_ATM(qnt_h2o, h2o);
3280 SET_ATM(qnt_o3, o3);
3281 SET_ATM(qnt_lwc, lwc);
3282 SET_ATM(qnt_rwc, rwc);
3283 SET_ATM(qnt_iwc, iwc);
3284 SET_ATM(qnt_swc, swc);
3285 SET_ATM(qnt_cc, cc);
3286 SET_ATM(qnt_pct, pct);
3287 SET_ATM(qnt_pcb, pcb);
3288 SET_ATM(qnt_cl, cl);
3289 SET_ATM(qnt_plcl, plcl);
3290 SET_ATM(qnt_plfc, plfc);
3291 SET_ATM(qnt_pel, pel);
3292 SET_ATM(qnt_cape, cape);
3293 SET_ATM(qnt_cin, cin);
3294 SET_ATM(qnt_o3c, o3c);
3295 SET_ATM(qnt_hno3,
3296 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3297 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3298 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3299 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3300 atm->lat[ip], atm->p[ip]));
3301 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3302 atm->lat[ip], atm->p[ip]));
3303 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3304 atm->lat[ip], atm->p[ip]));
3305 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3306 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3307 SET_ATM(qnt_psat, PSAT(t));
3308 SET_ATM(qnt_psice, PSICE(t));
3309 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3310 SET_ATM(qnt_sh, SH(h2o));
3311 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3312 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3313 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3314 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3315 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3316 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3317 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3318 SET_ATM(qnt_pv, pv);
3319 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3320 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3321 SET_ATM(qnt_tnat,
3322 nat_temperature(atm->p[ip], h2o,
3323 clim_zm(&clim->hno3, atm->time[ip],
3324 atm->lat[ip], atm->p[ip])));
3325 SET_ATM(qnt_tsts,
3326 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3327 }
3328}
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:4191
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:1891
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1704
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1364
#define H0
Scale height [km].
Definition: mptrac.h:177
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1337
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1605
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1441
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:777
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1411
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1580
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1313
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3303
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2408
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2402
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2405
Here is the call graph for this function:

◆ module_mixing()

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

Update atmospheric properties through interparcel mixing.

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

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

Definition at line 3332 of file mptrac.c.

3336 {
3337
3338 /* Set timer... */
3339 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
3340
3341 /* Allocate... */
3342 const int np = atm->np;
3343 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3344 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3345 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3346
3347 /* Set grid box size... */
3348 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3349 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3350 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3351
3352 /* Set time interval... */
3353 const double t0 = t - 0.5 * ctl->dt_mod;
3354 const double t1 = t + 0.5 * ctl->dt_mod;
3355
3356 /* Get indices... */
3357#ifdef _OPENACC
3358#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3359#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3360#pragma acc parallel loop independent gang vector
3361#else
3362#pragma omp parallel for default(shared)
3363#endif
3364 for (int ip = 0; ip < np; ip++) {
3365 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3366 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3367 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3368 if (atm->time[ip] < t0 || atm->time[ip] > t1
3369 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3370 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3371 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3372 izs[ip] = -1;
3373 }
3374
3375 /* Calculate interparcel mixing... */
3376 if (ctl->qnt_m >= 0)
3377 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_m);
3378 if (ctl->qnt_vmr >= 0)
3379 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_vmr);
3380 if (ctl->qnt_Ch2o >= 0)
3381 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o);
3382 if (ctl->qnt_Co3 >= 0)
3383 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3);
3384 if (ctl->qnt_Cco >= 0)
3385 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cco);
3386 if (ctl->qnt_Coh >= 0)
3387 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Coh);
3388 if (ctl->qnt_Ch >= 0)
3389 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch);
3390 if (ctl->qnt_Cho2 >= 0)
3391 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cho2);
3392 if (ctl->qnt_Ch2o2 >= 0)
3393 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o2);
3394 if (ctl->qnt_Co1d >= 0)
3395 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co1d);
3396 if (ctl->qnt_Co3p >= 0)
3397 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3p);
3398 if (ctl->qnt_Cccl4 >= 0)
3399 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl4);
3400 if (ctl->qnt_Cccl3f >= 0)
3401 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl3f);
3402 if (ctl->qnt_Cccl2f2 >= 0)
3403 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl2f2);
3404 if (ctl->qnt_Cn2o >= 0)
3405 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cn2o);
3406 if (ctl->qnt_Csf6 >= 0)
3407 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Csf6);
3408 if (ctl->qnt_aoa >= 0)
3409 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_aoa);
3410
3411 /* Free... */
3412#ifdef _OPENACC
3413#pragma acc exit data delete(ixs,iys,izs)
3414#endif
3415 free(ixs);
3416 free(iys);
3417 free(izs);
3418}
void module_mixing_help(const ctl_t *ctl, const clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, const int qnt_idx)
Perform interparcel mixing for a specific quantity.
Definition: mptrac.c:3422
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2423
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2780
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2777
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2435
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2774
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2420
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2789
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2426
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2792
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2429
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2771
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2783
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2795
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2438
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2432
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2786
Here is the call graph for this function:

◆ module_mixing_help()

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

Perform interparcel mixing for a specific quantity.

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

Parameters
ctlPointer to the control structure containing simulation parameters.
climPointer to the climate data structure containing climatological data.
atmPointer to the atmospheric data structure containing particle information.
ixsPointer to the array of grid box indices along the longitude direction.
iysPointer to the array of grid box indices along the latitude direction.
izsPointer to the array of grid box indices along the vertical direction.
qnt_idxIndex of the quantity for which mixing is performed.
Authors
Mingzhao Liu
Lars Hoffmann

Definition at line 3422 of file mptrac.c.

3429 {
3430
3431 /* Allocate... */
3432 const int np = atm->np;
3433 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
3434 double *restrict const cmean =
3435 (double *) malloc((size_t) ngrid * sizeof(double));
3436 int *restrict const count = (int *) malloc((size_t) ngrid * sizeof(int));
3437
3438 /* Init... */
3439#ifdef _OPENACC
3440#pragma acc enter data create(cmean[0:ngrid],count[0:ngrid])
3441#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
3442#pragma acc parallel loop independent gang vector
3443#else
3444#ifdef __NVCOMPILER
3445#pragma novector
3446#endif
3447#pragma omp parallel for
3448#endif
3449 for (int i = 0; i < ngrid; i++) {
3450 count[i] = 0;
3451 cmean[i] = 0;
3452 }
3453
3454 /* Loop over particles... */
3455#ifdef _OPENACC
3456#pragma acc parallel loop independent gang vector
3457#endif
3458 for (int ip = 0; ip < np; ip++)
3459 if (izs[ip] >= 0) {
3460 int idx = ARRAY_3D
3461 (ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz);
3462#ifdef _OPENACC
3463#pragma acc atomic update
3464#endif
3465 cmean[idx] += atm->q[qnt_idx][ip];
3466#ifdef _OPENACC
3467#pragma acc atomic update
3468#endif
3469 count[idx]++;
3470 }
3471#ifdef _OPENACC
3472#pragma acc parallel loop independent gang vector
3473#else
3474#ifdef __NVCOMPILER
3475#pragma novector
3476#endif
3477#pragma omp parallel for
3478#endif
3479 for (int i = 0; i < ngrid; i++)
3480 if (count[i] > 0)
3481 cmean[i] /= count[i];
3482
3483 /* Calculate interparcel mixing... */
3484#ifdef _OPENACC
3485#pragma acc parallel loop independent gang vector
3486#else
3487#pragma omp parallel for
3488#endif
3489 for (int ip = 0; ip < np; ip++)
3490 if (izs[ip] >= 0) {
3491
3492 /* Set mixing parameter... */
3493 double mixparam = 1.0;
3494 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
3495 double w =
3496 tropo_weight(clim, atm->time[ip], atm->lat[ip], atm->p[ip]);
3497 mixparam = w * ctl->mixing_trop + (1 - w) * ctl->mixing_strat;
3498 }
3499
3500 /* Adjust quantity... */
3501 atm->q[qnt_idx][ip] +=
3502 (cmean
3503 [ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz)]
3504 - atm->q[qnt_idx][ip]) * mixparam;
3505 }
3506
3507 /* Free... */
3508#ifdef _OPENACC
3509#pragma acc exit data delete(cmean,count)
3510#endif
3511 free(cmean);
3512 free(count);
3513}
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2765
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2768
Here is the call graph for this function:

◆ module_oh_chem()

void module_oh_chem ( const ctl_t ctl,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt 
)

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.
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.
dtArray of time steps for each particle.
Note
The function assumes that the necessary meteorological and climatological data structures have been initialized and are accessible via the pointers met0, met1, and clim, respectively.
The reaction rates are calculated based on the provided reaction mechanism and atmospheric conditions, including temperature, pressure, and the concentrations of relevant species.
The function updates the particle quantities based on the calculated reaction rates and the specified time steps. The update can include both mass and volume mixing ratio quantities, as determined by the control structure (ctl).
Authors
Lars Hoffmann
Mingzhao Liu

Definition at line 3517 of file mptrac.c.

3523 {
3524
3525 /* Set timer... */
3526 SELECT_TIMER("MODULE_OHCHEM", "PHYSICS", NVTX_GPU);
3527
3528 /* Check quantity flags... */
3529 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3530 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3531
3532 /* Parameter of SO2 correction... */
3533 const double a = 4.71572206e-08;
3534 const double b = -8.28782867e-01;
3535 const double low = pow(1 / a, 1 / b);
3536
3537 /* Loop over particles... */
3538 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,met0,met1,atm,dt)") {
3539
3540 /* Get temperature... */
3541 double t;
3543 INTPOL_3D(t, 1);
3544
3545 /* Calculate molecular density... */
3546 const double M = MOLEC_DENS(atm->p[ip], t);
3547
3548 /* Use constant reaction rate... */
3549 double k = NAN;
3550 if (ctl->oh_chem_reaction == 1)
3551 k = ctl->oh_chem[0];
3552
3553 /* Calculate bimolecular reaction rate... */
3554 else if (ctl->oh_chem_reaction == 2)
3555 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
3556
3557 /* Calculate termolecular reaction rate... */
3558 if (ctl->oh_chem_reaction == 3) {
3559
3560 /* Calculate rate coefficient for X + OH + M -> XOH + M
3561 (JPL Publication 19-05) ... */
3562 const double k0 =
3563 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
3564 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
3565 const double ki =
3566 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
3567 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
3568 double c = log10(k0 * M / ki);
3569 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
3570 }
3571
3572 /* Correction factor for high SO2 concentration
3573 (if qnt_Cx is defined, the correction is switched on)... */
3574 double cor = 1;
3575 if (ctl->qnt_Cx >= 0)
3576 cor =
3577 atm->q[ctl->qnt_Cx][ip] >
3578 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3579
3580 /* Calculate exponential decay... */
3581 const double rate_coef =
3582 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
3583 atm->lat[ip], atm->p[ip]) * M * cor;
3584 const double aux = exp(-dt[ip] * rate_coef);
3585 if (ctl->qnt_m >= 0) {
3586 if (ctl->qnt_mloss_oh >= 0)
3587 atm->q[ctl->qnt_mloss_oh][ip]
3588 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3589 atm->q[ctl->qnt_m][ip] *= aux;
3590 if (ctl->qnt_loss_rate >= 0)
3591 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3592 }
3593 if (ctl->qnt_vmr >= 0)
3594 atm->q[ctl->qnt_vmr][ip] *= aux;
3595 }
3596}
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2828
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2825
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2336
Here is the call graph for this function:

◆ module_position()

void module_position ( const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt 
)

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
ctlPointer to the control structure containing simulation parameters.
met0Pointer to the first meteorological data structure.
met1Pointer to the second meteorological data structure.
atmPointer to the atmospheric data structure containing particle information.
dtPointer to an array containing the time step for each particle.
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 3600 of file mptrac.c.

3605 {
3606
3607 /* Set timer... */
3608 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
3609
3610 /* Loop over particles... */
3611 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
3612
3613 /* Init... */
3614 double ps;
3616
3617 /* Calculate modulo... */
3618 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
3619 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
3620
3621 /* Check latitude... */
3622 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
3623 if (atm->lat[ip] > 90) {
3624 atm->lat[ip] = 180 - atm->lat[ip];
3625 atm->lon[ip] += 180;
3626 }
3627 if (atm->lat[ip] < -90) {
3628 atm->lat[ip] = -180 - atm->lat[ip];
3629 atm->lon[ip] += 180;
3630 }
3631 }
3632
3633 /* Check longitude... */
3634 while (atm->lon[ip] < -180)
3635 atm->lon[ip] += 360;
3636 while (atm->lon[ip] >= 180)
3637 atm->lon[ip] -= 360;
3638
3639 /* Check pressure... */
3640 if (atm->p[ip] < met0->p[met0->np - 1]) {
3641 if (ctl->reflect)
3642 atm->p[ip] = 2. * met0->p[met0->np - 1] - atm->p[ip];
3643 else
3644 atm->p[ip] = met0->p[met0->np - 1];
3645 } else if (atm->p[ip] > 300.) {
3646 INTPOL_2D(ps, 1);
3647 if (atm->p[ip] > ps) {
3648 if (ctl->reflect)
3649 atm->p[ip] = 2. * ps - atm->p[ip];
3650 else
3651 atm->p[ip] = ps;
3652 }
3653 }
3654 }
3655}
int reflect
Reflection of particles at top and bottom boundary (0=no, 1=yes).
Definition: mptrac.h:2639

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

3660 {
3661
3662 /* Initialize GSL random number generators... */
3663 gsl_rng_env_setup();
3664 if (omp_get_max_threads() > NTHREADS)
3665 ERRMSG("Too many threads!");
3666 for (int i = 0; i < NTHREADS; i++) {
3667 rng[i] = gsl_rng_alloc(gsl_rng_default);
3668 gsl_rng_set(rng[i], gsl_rng_default_seed
3669 + (long unsigned) (ntask * NTHREADS + i));
3670 }
3671
3672 /* Initialize cuRAND random number generators... */
3673#ifdef CURAND
3674 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
3675 CURAND_STATUS_SUCCESS)
3676 ERRMSG("Cannot create random number generator!");
3677 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
3678 CURAND_STATUS_SUCCESS)
3679 ERRMSG("Cannot set seed for random number generator!");
3680 if (curandSetStream
3681 (rng_curand,
3682 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
3683 CURAND_STATUS_SUCCESS)
3684 ERRMSG("Cannot set stream for random number generator!");
3685#endif
3686}
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:284

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

3694 {
3695
3696 /* Use GSL random number generators... */
3697 if (ctl->rng_type == 0) {
3698
3699 /* Uniform distribution... */
3700 if (method == 0) {
3701#pragma omp parallel for default(shared)
3702 for (size_t i = 0; i < n; ++i)
3703 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
3704 }
3705
3706 /* Normal distribution... */
3707 else if (method == 1) {
3708#pragma omp parallel for default(shared)
3709 for (size_t i = 0; i < n; ++i)
3710 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
3711 }
3712
3713 /* Update of random numbers on device... */
3714#ifdef _OPENACC
3715#pragma acc update device(rs[:n])
3716#endif
3717 }
3718
3719 /* Use Squares random number generator (Widynski, 2022)... */
3720 else if (ctl->rng_type == 1) {
3721
3722 /* Set key (don't change this!)... */
3723 const uint64_t key = 0xc8e4fd154ce32f6d;
3724
3725 /* Uniform distribution... */
3726#ifdef _OPENACC
3727#pragma acc data present(rs)
3728#pragma acc parallel loop independent gang vector
3729#else
3730#pragma omp parallel for default(shared)
3731#endif
3732 for (size_t i = 0; i < n + 1; ++i) {
3733 uint64_t r, t, x, y, z;
3734 y = x = (rng_ctr + i) * key;
3735 z = y + key;
3736 x = x * x + y;
3737 x = (x >> 32) | (x << 32);
3738 x = x * x + z;
3739 x = (x >> 32) | (x << 32);
3740 x = x * x + y;
3741 x = (x >> 32) | (x << 32);
3742 t = x = x * x + z;
3743 x = (x >> 32) | (x << 32);
3744 r = t ^ ((x * x + y) >> 32);
3745 rs[i] = (double) r / (double) UINT64_MAX;
3746 }
3747 rng_ctr += n + 1;
3748
3749 /* Normal distribution... */
3750 if (method == 1) {
3751#ifdef _OPENACC
3752#pragma acc parallel loop independent gang vector
3753#else
3754#pragma omp parallel for default(shared)
3755#endif
3756 for (size_t i = 0; i < n; i += 2) {
3757 const double r = sqrt(-2.0 * log(rs[i]));
3758 const double phi = 2.0 * M_PI * rs[i + 1];
3759 rs[i] = r * cosf((float) phi);
3760 rs[i + 1] = r * sinf((float) phi);
3761 }
3762 }
3763 }
3764
3765 /* Use cuRAND random number generators... */
3766 else if (ctl->rng_type == 2) {
3767#ifdef CURAND
3768#pragma acc host_data use_device(rs)
3769 {
3770
3771 /* Uniform distribution... */
3772 if (method == 0) {
3773 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
3774 CURAND_STATUS_SUCCESS)
3775 ERRMSG("Cannot create random numbers!");
3776 }
3777
3778 /* Normal distribution... */
3779 else if (method == 1) {
3780 if (curandGenerateNormalDouble
3781 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
3782 1.0) != CURAND_STATUS_SUCCESS)
3783 ERRMSG("Cannot create random numbers!");
3784 }
3785 }
3786#else
3787 ERRMSG("MPTRAC was compiled without cuRAND!");
3788#endif
3789 }
3790}
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2642

◆ module_sedi()

void module_sedi ( const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt 
)

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.
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.
dtPointer to the array of time steps for each particle.
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 3794 of file mptrac.c.

3799 {
3800
3801 /* Set timer... */
3802 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
3803
3804 /* Loop over particles... */
3805 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
3806
3807 /* Get temperature... */
3808 double t;
3810 INTPOL_3D(t, 1);
3811
3812 /* Sedimentation velocity... */
3813 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3814 atm->q[ctl->qnt_rhop][ip]);
3815
3816 /* Calculate pressure change... */
3817 atm->p[ip] += DZ2DP(v_s * dt[ip] / 1000., atm->p[ip]);
3818 }
3819}
Here is the call graph for this function:

◆ module_sort()

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

Sort particles according to box index.

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

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

Definition at line 3823 of file mptrac.c.

3826 {
3827
3828 /* Set timer... */
3829 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
3830
3831 /* Allocate... */
3832 const int np = atm->np;
3833 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
3834 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
3835
3836#ifdef _OPENACC
3837#pragma acc enter data create(a[0:np],p[0:np])
3838#pragma acc data present(ctl,met0,atm,a,p)
3839#endif
3840
3841 /* Get box index... */
3842#ifdef _OPENACC
3843#pragma acc parallel loop independent gang vector
3844#else
3845#pragma omp parallel for default(shared)
3846#endif
3847 for (int ip = 0; ip < np; ip++) {
3848 a[ip] =
3849 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
3850 locate_reg(met0->lat, met0->ny, atm->lat[ip]))
3851 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
3852 p[ip] = ip;
3853 }
3854
3855 /* Sorting... */
3856#ifdef _OPENACC
3857#pragma acc host_data use_device(a, p)
3858#endif
3859#ifdef THRUST
3860 thrustSortWrapper(a, np, p);
3861#else
3862 ERRMSG("MPTRAC was compiled without Thrust library!");
3863#endif
3864
3865 /* Sort data... */
3866 module_sort_help(atm->time, p, np);
3867 module_sort_help(atm->p, p, np);
3868 module_sort_help(atm->lon, p, np);
3869 module_sort_help(atm->lat, p, np);
3870 for (int iq = 0; iq < ctl->nq; iq++)
3871 module_sort_help(atm->q[iq], p, np);
3872
3873 /* Free... */
3874#ifdef _OPENACC
3875#pragma acc exit data delete(a,p)
3876#endif
3877 free(a);
3878 free(p);
3879}
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:3883
void thrustSortWrapper(double *__restrict__ c, int n, int *__restrict__ index)
Wrapper to Thrust sorting function.
int nq
Number of quantities.
Definition: mptrac.h:2180
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 3883 of file mptrac.c.

3886 {
3887
3888 /* Allocate... */
3889 double *restrict const help =
3890 (double *) malloc((size_t) np * sizeof(double));
3891
3892 /* Reordering of array... */
3893#ifdef _OPENACC
3894#pragma acc enter data create(help[0:np])
3895#pragma acc data present(a,p,help)
3896#pragma acc parallel loop independent gang vector
3897#else
3898#pragma omp parallel for default(shared)
3899#endif
3900 for (int ip = 0; ip < np; ip++)
3901 help[ip] = a[p[ip]];
3902#ifdef _OPENACC
3903#pragma acc parallel loop independent gang vector
3904#else
3905#pragma omp parallel for default(shared)
3906#endif
3907 for (int ip = 0; ip < np; ip++)
3908 a[ip] = help[ip];
3909
3910 /* Free... */
3911#ifdef _OPENACC
3912#pragma acc exit data delete(help)
3913#endif
3914 free(help);
3915}

◆ module_timesteps()

void module_timesteps ( const ctl_t ctl,
met_t met0,
atm_t atm,
double *  dt,
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.
met0Pointer to the initial meteorological data structure.
atmPointer to the atmospheric data structure containing air parcel information.
dtPointer to the array storing the calculated time steps for air parcels.
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 3919 of file mptrac.c.

3924 {
3925
3926 /* Set timer... */
3927 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3928
3929 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
3930 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
3931
3932 const int local =
3933 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
3934
3935 /* Loop over particles... */
3936 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,atm,met0,dt)") {
3937
3938 /* Set time step for each air parcel... */
3939 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
3940 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
3941 && ctl->direction * (atm->time[ip] - t) < 0))
3942 dt[ip] = t - atm->time[ip];
3943 else
3944 dt[ip] = 0.0;
3945
3946 /* Check horizontal boundaries of local meteo data... */
3947 if (local && (atm->lon[ip] <= met0->lon[0]
3948 || atm->lon[ip] >= met0->lon[met0->nx - 1]
3949 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
3950 dt[ip] = 0.0;
3951 }
3952}

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

3958 {
3959
3960 /* Set timer... */
3961 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3962
3963 /* Set start time... */
3964 if (ctl->direction == 1) {
3965 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3966 if (ctl->t_stop > 1e99)
3967 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3968 } else {
3969 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3970 if (ctl->t_stop > 1e99)
3971 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3972 }
3973
3974 /* Check time interval... */
3975 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
3976 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
3977
3978 /* Round start time... */
3979 if (ctl->direction == 1)
3980 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
3981 else
3982 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
3983}

◆ module_tracer_chem()

void module_tracer_chem ( const ctl_t ctl,
const clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt 
)

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.
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.
dtPointer to an array containing the time step for each particle.
Note
The function assumes that the necessary control structure (ctl), climatological data structure (clim), meteorological data structures (met0, met1), and atmospheric data structure (atm) have been initialized and are accessible.
Chemical reactions involving CFC-10, CFC-11, CFC-12, and N2O are simulated for each particle in the atmospheric data structure.
The function calculates reaction rates based on temperature, solar zenith angle, total column ozone, and the volume mixing ratio of O(1D).
The exponential decay of tracer concentrations due to chemical reactions is calculated using reaction rate coefficients and the time step (dt) for each particle.
If the particle has a quantity flag for the tracer species (e.g., ctl->qnt_Cccl4, ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o), the function updates the concentration of the tracer based on the exponential decay.
Authors
Mingzhao Liu
Lars Hoffmann

Definition at line 3987 of file mptrac.c.

3993 {
3994
3995 /* Set timer... */
3996 SELECT_TIMER("MODULE_TRACERCHEM", "PHYSICS", NVTX_GPU);
3997
3998 /* Loop over particles... */
3999 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,met0,atm,met1,dt)") {
4000
4001 /* Get temperature... */
4002 double t;
4004 INTPOL_3D(t, 1);
4005
4006 /* Get molecular density... */
4007 const double M = MOLEC_DENS(atm->p[ip], t);
4008
4009 /* Get total column ozone... */
4010 double o3c;
4011 INTPOL_2D(o3c, 1);
4012
4013 /* Get solar zenith angle... */
4014 const double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
4015
4016 /* Get O(1D) volume mixing ratio... */
4017 const double o1d =
4018 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4019
4020 /* Reactions for CFC-10... */
4021 if (ctl->qnt_Cccl4 >= 0) {
4022 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4023 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4024 atm->p[ip], sza, o3c);
4025 atm->q[ctl->qnt_Cccl4][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
4026 }
4027
4028 /* Reactions for CFC-11... */
4029 if (ctl->qnt_Cccl3f >= 0) {
4030 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4031 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4032 atm->p[ip], sza, o3c);
4033 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
4034 }
4035
4036 /* Reactions for CFC-12... */
4037 if (ctl->qnt_Cccl2f2 >= 0) {
4038 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4039 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4040 atm->p[ip], sza, o3c);
4041 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
4042 }
4043
4044 /* Reactions for N2O... */
4045 if (ctl->qnt_Cn2o >= 0) {
4046 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4047 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4048 atm->p[ip], sza, o3c);
4049 atm->q[ctl->qnt_Cn2o][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
4050 }
4051 }
4052}
double clim_photo(const double rate[CP][CSZA][CO3], const clim_photo_t *photo, const double p, const double sza, const double o3c)
Calculates the photolysis rate for a given set of atmospheric conditions.
Definition: mptrac.c:149
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:414
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3204
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3201
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3195
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3198
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3300
Here is the call graph for this function:

◆ module_wet_deposition()

void module_wet_deposition ( const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
const double *  dt 
)

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.
met0Pointer to the initial meteorological data structure.
met1Pointer to the updated meteorological data structure.
atmPointer to the atmospheric data structure containing air parcel information.
dtArray containing the time step for each air parcel.
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.
Authors
Lars Hoffmann
Mingzhao Liu

Definition at line 4056 of file mptrac.c.

4061 {
4062
4063 /* Set timer... */
4064 SELECT_TIMER("MODULE_WETDEPO", "PHYSICS", NVTX_GPU);
4065
4066 /* Check quantity flags... */
4067 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4068 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4069
4070 /* Loop over particles... */
4071 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
4072
4073 /* Check whether particle is below cloud top... */
4074 double pct;
4076 INTPOL_2D(pct, 1);
4077 if (!isfinite(pct) || atm->p[ip] <= pct)
4078 continue;
4079
4080 /* Get cloud bottom pressure... */
4081 double pcb;
4082 INTPOL_2D(pcb, 0);
4083
4084 /* Estimate precipitation rate (Pisso et al., 2019)... */
4085 double cl;
4086 INTPOL_2D(cl, 0);
4087 const double Is =
4088 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4089 if (Is < 0.01)
4090 continue;
4091
4092 /* Check whether particle is inside or below cloud... */
4093 double lwc, rwc, iwc, swc;
4094 INTPOL_3D(lwc, 1);
4095 INTPOL_3D(rwc, 0);
4096 INTPOL_3D(iwc, 0);
4097 INTPOL_3D(swc, 0);
4098 int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4099
4100 /* Get temperature... */
4101 double t;
4102 INTPOL_3D(t, 0);
4103
4104 /* Calculate in-cloud scavenging coefficient... */
4105 double lambda = 0;
4106 if (inside) {
4107
4108 /* Calculate retention factor... */
4109 double eta;
4110 if (t > 273.15)
4111 eta = 1;
4112 else if (t <= 238.15)
4113 eta = ctl->wet_depo_ic_ret_ratio;
4114 else
4115 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4116
4117 /* Use exponential dependency for particles ... */
4118 if (ctl->wet_depo_ic_a > 0)
4119 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4120
4121 /* Use Henry's law for gases... */
4122 else if (ctl->wet_depo_ic_h[0] > 0) {
4123
4124 /* Get Henry's constant (Sander, 2015)... */
4125 double h = ctl->wet_depo_ic_h[0]
4126 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4127
4128 /* Use effective Henry's constant for SO2
4129 (Berglen, 2004; Simpson, 2012)... */
4130 if (ctl->wet_depo_ic_h[2] > 0) {
4131 const double H_ion = pow(10, ctl->wet_depo_ic_h[2] * (-1));
4132 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4133 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4134 h *= (1 + K_1 / H_ion + K_1 * K_2 / pow(H_ion, 2));
4135 }
4136
4137 /* Estimate depth of cloud layer... */
4138 const double dz = 1e3 * (Z(pct) - Z(pcb));
4139
4140 /* Calculate scavenging coefficient (Draxler and Hess, 1997)... */
4141 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4142 }
4143 }
4144
4145 /* Calculate below-cloud scavenging coefficient... */
4146 else {
4147
4148 /* Calculate retention factor... */
4149 double eta;
4150 if (t > 270)
4151 eta = 1;
4152 else
4153 eta = ctl->wet_depo_bc_ret_ratio;
4154
4155 /* Use exponential dependency for particles... */
4156 if (ctl->wet_depo_bc_a > 0)
4157 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4158
4159 /* Use Henry's law for gases... */
4160 else if (ctl->wet_depo_bc_h[0] > 0) {
4161
4162 /* Get Henry's constant (Sander, 2015)... */
4163 const double h = ctl->wet_depo_bc_h[0]
4164 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4165
4166 /* Estimate depth of cloud layer... */
4167 const double dz = 1e3 * (Z(pct) - Z(pcb));
4168
4169 /* Calculate scavenging coefficient (Draxler and Hess, 1997)... */
4170 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4171 }
4172 }
4173
4174 /* Calculate exponential decay of mass... */
4175 const double aux = exp(-dt[ip] * lambda);
4176 if (ctl->qnt_m >= 0) {
4177 if (ctl->qnt_mloss_wet >= 0)
4178 atm->q[ctl->qnt_mloss_wet][ip]
4179 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4180 atm->q[ctl->qnt_m][ip] *= aux;
4181 if (ctl->qnt_loss_rate >= 0)
4182 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4183 }
4184 if (ctl->qnt_vmr >= 0)
4185 atm->q[ctl->qnt_vmr][ip] *= aux;
4186 }
4187}
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2855
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2849
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2345
double wet_depo_ic_h[3]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb, pH).
Definition: mptrac.h:2861
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2846
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2864
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2870
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2867
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2858
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2852

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

4194 {
4195
4196 /* Check water vapor volume mixing ratio... */
4197 const double h2o_help = MAX(h2o, 0.1e-6);
4198
4199 /* Calculate T_NAT... */
4200 const double p_hno3 = hno3 * p / 1.333224;
4201 const double p_h2o = h2o_help * p / 1.333224;
4202 const double a = 0.009179 - 0.00088 * log10(p_h2o);
4203 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
4204 const double c = -11397.0 / a;
4205 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
4206 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
4207 if (x2 > 0)
4208 tnat = x2;
4209
4210 return tnat;
4211}

◆ read_atm()

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

4218 {
4219
4220 int result;
4221
4222 /* Set timer... */
4223 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
4224
4225 /* Init... */
4226 atm->np = 0;
4227
4228 /* Write info... */
4229 LOG(1, "Read atmospheric data: %s", filename);
4230
4231 /* Read ASCII data... */
4232 if (ctl->atm_type == 0)
4233 result = read_atm_asc(filename, ctl, atm);
4234
4235 /* Read binary data... */
4236 else if (ctl->atm_type == 1)
4237 result = read_atm_bin(filename, ctl, atm);
4238
4239 /* Read netCDF data... */
4240 else if (ctl->atm_type == 2)
4241 result = read_atm_nc(filename, ctl, atm);
4242
4243 /* Read CLaMS data... */
4244 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
4245 result = read_atm_clams(filename, ctl, atm);
4246
4247 /* Error... */
4248 else
4249 ERRMSG("Atmospheric data type not supported!");
4250
4251 /* Check result... */
4252 if (result != 1)
4253 return 0;
4254
4255 /* Check number of air parcels... */
4256 if (atm->np < 1)
4257 ERRMSG("Can not read any data!");
4258
4259 /* Write info... */
4260 double mini, maxi;
4261 LOG(2, "Number of particles: %d", atm->np);
4262 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
4263 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
4264 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
4265 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
4266 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
4267 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
4268 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
4269 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
4270 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
4271 for (int iq = 0; iq < ctl->nq; iq++) {
4272 char msg[5 * LEN];
4273 sprintf(msg, "Quantity %s range: %s ... %s %s",
4274 ctl->qnt_name[iq], ctl->qnt_format[iq],
4275 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
4276 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
4277 LOG(2, msg, mini, maxi);
4278 }
4279
4280 /* Return success... */
4281 return 1;
4282}
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:4440
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:4328
int read_atm_clams(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a CLaMS netCDF file and populates the given atmospheric structure.
Definition: mptrac.c:4384
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:4286
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2192
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:2905
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2189
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2183
Here is the call graph for this function:

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

4289 {
4290
4291 /* Open file... */
4292 FILE *in;
4293 if (!(in = fopen(filename, "r"))) {
4294 WARN("Cannot open file!");
4295 return 0;
4296 }
4297
4298 /* Read line... */
4299 char line[LEN];
4300 while (fgets(line, LEN, in)) {
4301
4302 /* Read data... */
4303 char *tok;
4304 TOK(line, tok, "%lg", atm->time[atm->np]);
4305 TOK(NULL, tok, "%lg", atm->p[atm->np]);
4306 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
4307 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
4308 for (int iq = 0; iq < ctl->nq; iq++)
4309 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
4310
4311 /* Convert altitude to pressure... */
4312 atm->p[atm->np] = P(atm->p[atm->np]);
4313
4314 /* Increment data point counter... */
4315 if ((++atm->np) > NP)
4316 ERRMSG("Too many data points!");
4317 }
4318
4319 /* Close file... */
4320 fclose(in);
4321
4322 /* Return success... */
4323 return 1;
4324}
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1679

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

4331 {
4332
4333 /* Open file... */
4334 FILE *in;
4335 if (!(in = fopen(filename, "r")))
4336 return 0;
4337
4338 /* Check version of binary data... */
4339 int version;
4340 FREAD(&version, int,
4341 1,
4342 in);
4343 if (version != 100)
4344 ERRMSG("Wrong version of binary data!");
4345
4346 /* Read data... */
4347 FREAD(&atm->np, int,
4348 1,
4349 in);
4350 FREAD(atm->time, double,
4351 (size_t) atm->np,
4352 in);
4353 FREAD(atm->p, double,
4354 (size_t) atm->np,
4355 in);
4356 FREAD(atm->lon, double,
4357 (size_t) atm->np,
4358 in);
4359 FREAD(atm->lat, double,
4360 (size_t) atm->np,
4361 in);
4362 for (int iq = 0; iq < ctl->nq; iq++)
4363 FREAD(atm->q[iq], double,
4364 (size_t) atm->np,
4365 in);
4366
4367 /* Read final flag... */
4368 int final;
4369 FREAD(&final, int,
4370 1,
4371 in);
4372 if (final != 999)
4373 ERRMSG("Error while reading binary data!");
4374
4375 /* Close file... */
4376 fclose(in);
4377
4378 /* Return success... */
4379 return 1;
4380}

◆ read_atm_clams()

int read_atm_clams ( const char *  filename,
const ctl_t ctl,
atm_t atm 
)

Reads air parcel data from a CLaMS netCDF file and populates the given atmospheric structure.

This function reads air parcel data from a CLaMS (Chemical Lagrangian Model of the Stratosphere) netCDF file and stores the data in the provided atm_t structure. It handles various coordinate systems and ensures the necessary data is correctly read and stored.

Parameters
filenameThe name of the netCDF file containing the atmospheric data.
ctlA pointer to the control structure (ctl_t) that specifies the vertical coordinate system and 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 netCDF file for reading.
  • Returns 0 if the file cannot be opened.
  • Retrieves the number of particles (np) from the "NPARTS" dimension.
  • Reads the initial time (TIME_INIT) if available, otherwise uses the "time" variable.
  • Reads the vertical coordinate data based on the specified system (vert_coord_ap):
    • If vert_coord_ap is 1, reads "ZETA" and optionally "PRESS".
    • Otherwise, reads "PRESS_INIT" if available, otherwise uses "PRESS".
  • Reads the longitude ("LON") and latitude ("LAT") data.
  • Closes the netCDF file.
  • 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.
  • WARN for logging warnings.
Author
Jan Clemens

Definition at line 4384 of file mptrac.c.

4387 {
4388
4389 int ncid, varid;
4390
4391 /* Open file... */
4392 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
4393 return 0;
4394
4395 /* Get dimensions... */
4396 NC_INQ_DIM("NPARTS", &atm->np, 1, NP);
4397
4398 /* Get time... */
4399 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
4400 NC(nc_get_var_double(ncid, varid, atm->time));
4401 } else {
4402 WARN("TIME_INIT not found use time instead!");
4403 double time_init;
4404 NC_GET_DOUBLE("time", &time_init, 1);
4405 for (int ip = 0; ip < atm->np; ip++) {
4406 atm->time[ip] = time_init;
4407 }
4408 }
4409
4410 /* Read zeta coordinate, pressure is optional... */
4411 if (ctl->advect_vert_coord == 1) {
4412 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
4413 NC_GET_DOUBLE("PRESS", atm->p, 0);
4414 }
4415
4416 /* Read pressure, zeta coordinate is optional... */
4417 else {
4418 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
4419 NC(nc_get_var_double(ncid, varid, atm->p));
4420 } else {
4421 WARN("PRESS_INIT not found use PRESS instead!");
4422 nc_inq_varid(ncid, "PRESS", &varid);
4423 NC(nc_get_var_double(ncid, varid, atm->p));
4424 }
4425 }
4426
4427 /* Read longitude and latitude... */
4428 NC_GET_DOUBLE("LON", atm->lon, 1);
4429 NC_GET_DOUBLE("LAT", atm->lat, 1);
4430
4431 /* Close file... */
4432 NC(nc_close(ncid));
4433
4434 /* Return success... */
4435 return 1;
4436}
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1001
#define NC_INQ_DIM(dimname, ptr, min, max)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1088
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1060

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

4443 {
4444
4445 int ncid, varid;
4446
4447 /* Open file... */
4448 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
4449 return 0;
4450
4451 /* Get dimensions... */
4452 NC_INQ_DIM("obs", &atm->np, 1, NP);
4453
4454 /* Read geolocations... */
4455 NC_GET_DOUBLE("time", atm->time, 1);
4456 NC_GET_DOUBLE("press", atm->p, 1);
4457 NC_GET_DOUBLE("lon", atm->lon, 1);
4458 NC_GET_DOUBLE("lat", atm->lat, 1);
4459
4460 /* Read variables... */
4461 for (int iq = 0; iq < ctl->nq; iq++)
4462 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
4463
4464 /* Close file... */
4465 NC(nc_close(ncid));
4466
4467 /* Return success... */
4468 return 1;
4469}

◆ read_clim()

void read_clim ( const ctl_t ctl,
clim_t clim 
)

Reads various climatological data and populates the given climatology structure.

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

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

This function performs the following steps:

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

The function utilizes several helper functions:

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

Definition at line 4473 of file mptrac.c.

4475 {
4476
4477 /* Set timer... */
4478 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
4479
4480 /* Init tropopause climatology... */
4481 clim_tropo_init(clim);
4482
4483 /* Read photolysis rates... */
4484 if (ctl->clim_photo[0] != '-')
4485 read_clim_photo(ctl->clim_photo, &clim->photo);
4486
4487 /* Read HNO3 climatology... */
4488 if (ctl->clim_hno3_filename[0] != '-')
4489 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
4490
4491 /* Read OH climatology... */
4492 if (ctl->clim_oh_filename[0] != '-') {
4493 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
4494 if (ctl->oh_chem_beta > 0)
4495 clim_oh_diurnal_correction(ctl, clim);
4496 }
4497
4498 /* Read H2O2 climatology... */
4499 if (ctl->clim_h2o2_filename[0] != '-')
4500 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
4501
4502 /* Read HO2 climatology... */
4503 if (ctl->clim_ho2_filename[0] != '-')
4504 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
4505
4506 /* Read O(1D) climatology... */
4507 if (ctl->clim_o1d_filename[0] != '-')
4508 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
4509
4510 /* Read CFC-10 time series... */
4511 if (ctl->clim_ccl4_timeseries[0] != '-')
4513
4514 /* Read CFC-11 time series... */
4515 if (ctl->clim_ccl3f_timeseries[0] != '-')
4517
4518 /* Read CFC-12 time series... */
4519 if (ctl->clim_ccl2f2_timeseries[0] != '-')
4521
4522 /* Read N2O time series... */
4523 if (ctl->clim_n2o_timeseries[0] != '-')
4524 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
4525
4526 /* Read SF6 time series... */
4527 if (ctl->clim_sf6_timeseries[0] != '-')
4528 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
4529}
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:4533
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:4652
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:4706
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:228
void clim_oh_diurnal_correction(const ctl_t *ctl, clim_t *clim)
Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data.
Definition: mptrac.c:116
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2738
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2741
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2726
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2735
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2732
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2729
Here is the call graph for this function:

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

4535 {
4536
4537 int ncid, varid;
4538
4539 /* Write info... */
4540 LOG(1, "Read photolysis rates: %s", filename);
4541
4542 /* Open netCDF file... */
4543 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
4544 WARN("Photolysis rate data are missing!");
4545 return;
4546 }
4547
4548 /* Read pressure data... */
4549 NC_INQ_DIM("press", &photo->np, 2, CP);
4550 NC_GET_DOUBLE("press", photo->p, 1);
4551 if (photo->p[0] < photo->p[1])
4552 ERRMSG("Pressure data are not descending!");
4553
4554 /* Read total column ozone data... */
4555 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3);
4556 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
4557 if (photo->o3c[0] > photo->o3c[1])
4558 ERRMSG("Total column ozone data are not ascending!");
4559
4560 /* Read solar zenith angle data... */
4561 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA);
4562 NC_GET_DOUBLE("sza", photo->sza, 1);
4563 if (photo->sza[0] > photo->sza[1])
4564 ERRMSG("Solar zenith angle data are not ascending!");
4565
4566 /* Read data... */
4567 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
4568 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
4569 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
4570 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
4571 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
4572 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
4573 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
4574 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
4575 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
4576
4577 /* Close netCDF file... */
4578 NC(nc_close(ncid));
4579
4580 /* Write info... */
4581 LOG(2, "Number of pressure levels: %d", photo->np);
4582 LOG(2, "Altitude levels: %g, %g ... %g km",
4583 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
4584 LOG(2, "Pressure levels: %g, %g ... %g hPa",
4585 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
4586 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
4587 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
4588 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
4589 RAD2DEG(photo->sza[photo->nsza - 1]));
4590 LOG(2, "Number of total column ozone values: %d", photo->no3c);
4591 LOG(2, "Total column ozone: %g, %g ... %g DU",
4592 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
4593 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
4594 photo->n2o[0][0][0], photo->n2o[1][0][0],
4595 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4596 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
4597 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
4598 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4599 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
4600 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
4601 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4602 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
4603 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
4604 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4605 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
4606 photo->o2[0][0][0], photo->o2[1][0][0],
4607 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4608 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
4609 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
4610 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4611 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
4612 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
4613 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4614 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
4615 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
4616 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4617 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
4618 photo->h2o[0][0][0], photo->h2o[1][0][0],
4619 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4620}
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:4624
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:299
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:294
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:304
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3210
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3207
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3216
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3219
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3213
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 4624 of file mptrac.c.

4628 {
4629
4630 /* Allocate... */
4631 double *help;
4632 ALLOC(help, double,
4633 photo->np * photo->nsza * photo->no3c);
4634
4635 /* Read varible... */
4636 int varid;
4637 NC_GET_DOUBLE(varname, help, 1);
4638
4639 /* Copy data... */
4640 for (int ip = 0; ip < photo->np; ip++)
4641 for (int is = 0; is < photo->nsza; is++)
4642 for (int io = 0; io < photo->no3c; io++)
4643 var[ip][is][io] =
4644 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4645
4646 /* Free... */
4647 free(help);
4648}

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

4654 {
4655
4656 /* Write info... */
4657 LOG(1, "Read climatological time series: %s", filename);
4658
4659 /* Open file... */
4660 FILE *in;
4661 if (!(in = fopen(filename, "r"))) {
4662 WARN("Cannot open file!");
4663 return 0;
4664 }
4665
4666 /* Read data... */
4667 char line[LEN];
4668 int nh = 0;
4669 while (fgets(line, LEN, in))
4670 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
4671
4672 /* Convert years to seconds... */
4673 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
4674
4675 /* Check data... */
4676 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
4677 ERRMSG("Time series must be ascending!");
4678
4679 /* Count time steps... */
4680 if ((++nh) >= CTS)
4681 ERRMSG("Too many data points!");
4682 }
4683
4684 /* Close file... */
4685 fclose(in);
4686
4687 /* Check number of data points... */
4688 ts->ntime = nh;
4689 if (nh < 2)
4690 ERRMSG("Not enough data points!");
4691
4692 /* Write info... */
4693 LOG(2, "Number of time steps: %d", ts->ntime);
4694 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
4695 ts->time[nh - 1]);
4696 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
4697 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
4698 (size_t) nh));
4699
4700 /* Exit success... */
4701 return 1;
4702}
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:314

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

4709 {
4710
4711 int ncid, varid, it, iy, iz, iz2, nt;
4712
4713 double *help, varmin = 1e99, varmax = -1e99;
4714
4715 /* Write info... */
4716 LOG(1, "Read %s data: %s", varname, filename);
4717
4718 /* Open netCDF file... */
4719 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
4720 WARN("%s climatology data are missing!", varname);
4721 return;
4722 }
4723
4724 /* Read pressure data... */
4725 NC_INQ_DIM("press", &zm->np, 2, CP);
4726 NC_GET_DOUBLE("press", zm->p, 1);
4727 if (zm->p[0] < zm->p[1])
4728 ERRMSG("Pressure data are not descending!");
4729
4730 /* Read latitudes... */
4731 NC_INQ_DIM("lat", &zm->nlat, 2, CY);
4732 NC_GET_DOUBLE("lat", zm->lat, 1);
4733 if (zm->lat[0] > zm->lat[1])
4734 ERRMSG("Latitude data are not ascending!");
4735
4736 /* Set time data (for monthly means)... */
4737 zm->ntime = 12;
4738 zm->time[0] = 1209600.00;
4739 zm->time[1] = 3888000.00;
4740 zm->time[2] = 6393600.00;
4741 zm->time[3] = 9072000.00;
4742 zm->time[4] = 11664000.00;
4743 zm->time[5] = 14342400.00;
4744 zm->time[6] = 16934400.00;
4745 zm->time[7] = 19612800.00;
4746 zm->time[8] = 22291200.00;
4747 zm->time[9] = 24883200.00;
4748 zm->time[10] = 27561600.00;
4749 zm->time[11] = 30153600.00;
4750
4751 /* Check number of timesteps... */
4752 NC_INQ_DIM("time", &nt, 12, 12);
4753
4754 /* Read data... */
4755 ALLOC(help, double,
4756 zm->nlat * zm->np * zm->ntime);
4757 NC_GET_DOUBLE(varname, help, 1);
4758 for (it = 0; it < zm->ntime; it++)
4759 for (iz = 0; iz < zm->np; iz++)
4760 for (iy = 0; iy < zm->nlat; iy++)
4761 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
4762 free(help);
4763
4764 /* Fix data gaps... */
4765 for (it = 0; it < zm->ntime; it++)
4766 for (iy = 0; iy < zm->nlat; iy++)
4767 for (iz = 0; iz < zm->np; iz++) {
4768 if (zm->vmr[it][iz][iy] < 0) {
4769 for (iz2 = 0; iz2 < zm->np; iz2++)
4770 if (zm->vmr[it][iz2][iy] >= 0) {
4771 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
4772 break;
4773 }
4774 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
4775 if (zm->vmr[it][iz2][iy] >= 0) {
4776 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
4777 break;
4778 }
4779 }
4780 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
4781 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
4782 }
4783
4784 /* Close netCDF file... */
4785 NC(nc_close(ncid));
4786
4787 /* Write info... */
4788 LOG(2, "Number of time steps: %d", zm->ntime);
4789 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
4790 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
4791 LOG(2, "Number of pressure levels: %d", zm->np);
4792 LOG(2, "Altitude levels: %g, %g ... %g km",
4793 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
4794 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
4795 zm->p[1], zm->p[zm->np - 1]);
4796 LOG(2, "Number of latitudes: %d", zm->nlat);
4797 LOG(2, "Latitudes: %g, %g ... %g deg",
4798 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
4799 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
4800 varmax);
4801}
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:289

◆ read_ctl()

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

4809 {
4810
4811 /* Set timer... */
4812 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
4813
4814 /* Write info... */
4815 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
4816 "(executable: %s | version: %s | compiled: %s, %s)\n",
4817 argv[0], VERSION, __DATE__, __TIME__);
4818
4819 /* Initialize quantity indices... */
4820 ctl->qnt_idx = -1;
4821 ctl->qnt_ens = -1;
4822 ctl->qnt_stat = -1;
4823 ctl->qnt_m = -1;
4824 ctl->qnt_vmr = -1;
4825 ctl->qnt_rp = -1;
4826 ctl->qnt_rhop = -1;
4827 ctl->qnt_ps = -1;
4828 ctl->qnt_ts = -1;
4829 ctl->qnt_zs = -1;
4830 ctl->qnt_us = -1;
4831 ctl->qnt_vs = -1;
4832 ctl->qnt_lsm = -1;
4833 ctl->qnt_sst = -1;
4834 ctl->qnt_pbl = -1;
4835 ctl->qnt_pt = -1;
4836 ctl->qnt_tt = -1;
4837 ctl->qnt_zt = -1;
4838 ctl->qnt_h2ot = -1;
4839 ctl->qnt_zg = -1;
4840 ctl->qnt_p = -1;
4841 ctl->qnt_t = -1;
4842 ctl->qnt_rho = -1;
4843 ctl->qnt_u = -1;
4844 ctl->qnt_v = -1;
4845 ctl->qnt_w = -1;
4846 ctl->qnt_h2o = -1;
4847 ctl->qnt_o3 = -1;
4848 ctl->qnt_lwc = -1;
4849 ctl->qnt_rwc = -1;
4850 ctl->qnt_iwc = -1;
4851 ctl->qnt_swc = -1;
4852 ctl->qnt_cc = -1;
4853 ctl->qnt_pct = -1;
4854 ctl->qnt_pcb = -1;
4855 ctl->qnt_cl = -1;
4856 ctl->qnt_plcl = -1;
4857 ctl->qnt_plfc = -1;
4858 ctl->qnt_pel = -1;
4859 ctl->qnt_cape = -1;
4860 ctl->qnt_cin = -1;
4861 ctl->qnt_o3c = -1;
4862 ctl->qnt_hno3 = -1;
4863 ctl->qnt_oh = -1;
4864 ctl->qnt_h2o2 = -1;
4865 ctl->qnt_ho2 = -1;
4866 ctl->qnt_o1d = -1;
4867 ctl->qnt_mloss_oh = -1;
4868 ctl->qnt_mloss_h2o2 = -1;
4869 ctl->qnt_mloss_kpp = -1;
4870 ctl->qnt_mloss_wet = -1;
4871 ctl->qnt_mloss_dry = -1;
4872 ctl->qnt_mloss_decay = -1;
4873 ctl->qnt_loss_rate = -1;
4874 ctl->qnt_psat = -1;
4875 ctl->qnt_psice = -1;
4876 ctl->qnt_pw = -1;
4877 ctl->qnt_sh = -1;
4878 ctl->qnt_rh = -1;
4879 ctl->qnt_rhice = -1;
4880 ctl->qnt_theta = -1;
4881 ctl->qnt_zeta = -1;
4882 ctl->qnt_zeta_d = -1;
4883 ctl->qnt_tvirt = -1;
4884 ctl->qnt_lapse = -1;
4885 ctl->qnt_vh = -1;
4886 ctl->qnt_vz = -1;
4887 ctl->qnt_pv = -1;
4888 ctl->qnt_tdew = -1;
4889 ctl->qnt_tice = -1;
4890 ctl->qnt_tsts = -1;
4891 ctl->qnt_tnat = -1;
4892 ctl->qnt_Cx = -1;
4893 ctl->qnt_Ch2o = -1;
4894 ctl->qnt_Co3 = -1;
4895 ctl->qnt_Cco = -1;
4896 ctl->qnt_Coh = -1;
4897 ctl->qnt_Ch = -1;
4898 ctl->qnt_Cho2 = -1;
4899 ctl->qnt_Ch2o2 = -1;
4900 ctl->qnt_Co1d = -1;
4901 ctl->qnt_Co3p = -1;
4902 ctl->qnt_Cccl4 = -1;
4903 ctl->qnt_Cccl3f = -1;
4904 ctl->qnt_Cccl2f2 = -1;
4905 ctl->qnt_Cn2o = -1;
4906 ctl->qnt_Csf6 = -1;
4907 ctl->qnt_aoa = -1;
4908
4909 /* Read quantities... */
4910 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
4911 if (ctl->nq > NQ)
4912 ERRMSG("Too many quantities!");
4913 for (int iq = 0; iq < ctl->nq; iq++) {
4914
4915 /* Read quantity name and format... */
4916 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
4917 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
4918 ctl->qnt_longname[iq]);
4919 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
4920 ctl->qnt_format[iq]);
4921 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
4922 sprintf(ctl->qnt_format[iq], "%%.2f");
4923
4924 /* Try to identify quantity... */
4925 SET_QNT(qnt_idx, "idx", "particle index", "-")
4926 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
4927 SET_QNT(qnt_stat, "stat", "station flag", "-")
4928 SET_QNT(qnt_m, "m", "mass", "kg")
4929 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
4930 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
4931 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
4932 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
4933 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
4934 SET_QNT(qnt_zs, "zs", "surface height", "km")
4935 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
4936 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
4937 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
4938 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
4939 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
4940 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
4941 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
4942 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
4943 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
4944 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
4945 SET_QNT(qnt_p, "p", "pressure", "hPa")
4946 SET_QNT(qnt_t, "t", "temperature", "K")
4947 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
4948 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
4949 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
4950 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
4951 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
4952 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
4953 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
4954 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
4955 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
4956 SET_QNT(qnt_swc, "iwc", "cloud snow water content", "kg/kg")
4957 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
4958 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
4959 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
4960 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
4961 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
4962 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
4963 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
4964 SET_QNT(qnt_cape, "cape", "convective available potential energy",
4965 "J/kg")
4966 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
4967 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
4968 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
4969 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
4970 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
4971 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
4972 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
4973 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
4974 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2", "mass loss due to H2O2 chemistry",
4975 "kg")
4976 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
4977 "kg")
4978 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
4979 "kg")
4980 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
4981 "kg")
4982 SET_QNT(qnt_mloss_decay, "mloss_decay",
4983 "mass loss due to exponential decay", "kg")
4984 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
4985 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
4986 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
4987 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
4988 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
4989 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
4990 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
4991 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
4992 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
4993 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
4994 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
4995 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
4996 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
4997 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
4998 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
4999 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
5000 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
5001 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
5002 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
5003 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
5004 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
5005 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
5006 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
5007 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
5008 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
5009 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
5010 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
5011 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
5012 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
5013 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
5014 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
5015 "ppv")
5016 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
5017 "ppv")
5018 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
5019 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
5020 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
5021 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
5022 }
5023
5024 /* Vertical coordinates and velocities... */
5025 ctl->advect_vert_coord =
5026 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
5027 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 2)
5028 ERRMSG("Set advect_vert_coord to 0, 1, or 2!");
5029 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
5030 ERRMSG("Please add zeta to your quantities for diabatic calculations!");
5031 ctl->met_vert_coord =
5032 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
5033 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord != 1)
5034 ERRMSG
5035 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
5036 ctl->met_clams =
5037 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
5038 ctl->advect_cpl_zeta_and_press_modules =
5039 (int) scan_ctl(filename, argc, argv, "ADVECT_ZETA_PRESS_MODULES", -1, "1",
5040 NULL);
5041
5042 /* Time steps of simulation... */
5043 ctl->direction =
5044 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
5045 if (ctl->direction != -1 && ctl->direction != 1)
5046 ERRMSG("Set DIRECTION to -1 or 1!");
5047 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
5048 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
5049
5050 /* Meteo data... */
5051 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
5052 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
5053 ctl->met_convention =
5054 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
5055 ctl->met_type =
5056 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
5057 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
5058 ERRMSG
5059 ("Please use meteorological files in netcdf format for diabatic calculations.");
5060 ctl->met_nc_scale =
5061 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
5062 ctl->met_nc_level =
5063 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
5064 ctl->met_nc_quant =
5065 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
5066 ctl->met_zfp_prec =
5067 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", -1, "8", NULL);
5068 ctl->met_zfp_tol_t =
5069 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_T", -1, "5.0", NULL);
5070 ctl->met_zfp_tol_z =
5071 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_Z", -1, "0.5", NULL);
5072 ctl->met_cms_batch =
5073 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
5074 ctl->met_cms_heur =
5075 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
5076 ctl->met_cms_eps_z =
5077 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
5078 ctl->met_cms_eps_t =
5079 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
5080 ctl->met_cms_eps_u =
5081 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
5082 ctl->met_cms_eps_v =
5083 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
5084 ctl->met_cms_eps_w =
5085 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
5086 ctl->met_cms_eps_pv =
5087 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
5088 ctl->met_cms_eps_h2o =
5089 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
5090 ctl->met_cms_eps_o3 =
5091 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5092 ctl->met_cms_eps_lwc =
5093 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5094 ctl->met_cms_eps_rwc =
5095 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5096 ctl->met_cms_eps_iwc =
5097 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5098 ctl->met_cms_eps_swc =
5099 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5100 ctl->met_cms_eps_cc =
5101 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5102 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5103 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5104 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5105 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5106 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5107 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5108 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5109 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5110 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5111 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5112 ctl->met_detrend =
5113 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5114 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5115 if (ctl->met_np > EP)
5116 ERRMSG("Too many levels!");
5117 ctl->met_press_level_def =
5118 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5119 NULL);
5120 if (ctl->met_press_level_def >= 0) {
5121 level_definitions(ctl);
5122 } else {
5123 if (ctl->met_np > 0) {
5124 for (int ip = 0; ip < ctl->met_np; ip++)
5125 ctl->met_p[ip] =
5126 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5127 }
5128 }
5129 ctl->met_geopot_sx =
5130 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5131 ctl->met_geopot_sy =
5132 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5133 ctl->met_relhum =
5134 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5135 ctl->met_cape =
5136 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
5137 if (ctl->met_cape < 0 || ctl->met_cape > 1)
5138 ERRMSG("Set MET_CAPE to 0 or 1!");
5139 ctl->met_pbl =
5140 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "2", NULL);
5141 if (ctl->met_pbl < 0 || ctl->met_pbl > 2)
5142 ERRMSG("Set MET_PBL = 0 ... 2!");
5143 ctl->met_pbl_min =
5144 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
5145 ctl->met_pbl_max =
5146 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
5147 ctl->met_tropo =
5148 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5149 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5150 ERRMSG("Set MET_TROPO = 0 ... 5!");
5151 ctl->met_tropo_pv =
5152 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5153 ctl->met_tropo_theta =
5154 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5155 ctl->met_tropo_spline =
5156 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5157 ctl->met_dt_out =
5158 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5159 ctl->met_cache =
5160 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5161 ctl->met_mpi_share =
5162 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5163
5164 /* Sorting... */
5165 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5166
5167 /* Isosurface parameters... */
5168 ctl->isosurf =
5169 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5170 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5171
5172 /* Random number generator... */
5173 ctl->rng_type =
5174 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "0", NULL);
5175 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5176 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5177
5178 /* Advection parameters... */
5179 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
5180 if (!(ctl->advect == 0 || ctl->advect == 1
5181 || ctl->advect == 2 || ctl->advect == 4))
5182 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
5183 ctl->reflect =
5184 (int) scan_ctl(filename, argc, argv, "REFLECT", -1, "0", NULL);
5185
5186 /* Diffusion parameters... */
5187 ctl->turb_dx_trop =
5188 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5189 ctl->turb_dx_strat =
5190 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5191 ctl->turb_dz_trop =
5192 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5193 ctl->turb_dz_strat =
5194 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5195 ctl->turb_mesox =
5196 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5197 ctl->turb_mesoz =
5198 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5199
5200 /* Convection... */
5201 ctl->conv_cape
5202 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5203 ctl->conv_cin
5204 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5205 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5206 ctl->conv_mix_bot
5207 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_BOT", -1, "1", NULL);
5208 ctl->conv_mix_top
5209 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_TOP", -1, "1", NULL);
5210
5211 /* Boundary conditions... */
5212 ctl->bound_mass =
5213 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5214 ctl->bound_mass_trend =
5215 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5216 ctl->bound_vmr =
5217 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5218 ctl->bound_vmr_trend =
5219 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5220 ctl->bound_lat0 =
5221 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5222 ctl->bound_lat1 =
5223 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5224 ctl->bound_p0 =
5225 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5226 ctl->bound_p1 =
5227 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5228 ctl->bound_dps =
5229 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5230 ctl->bound_dzs =
5231 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5232 ctl->bound_zetas =
5233 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5234 ctl->bound_pbl =
5235 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5236
5237 /* Species parameters... */
5238 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5239 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5240 ctl->molmass = 120.907;
5241 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5242 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5243 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5244 ctl->molmass = 137.359;
5245 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5246 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5247 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5248 ctl->molmass = 16.043;
5249 ctl->oh_chem_reaction = 2;
5250 ctl->oh_chem[0] = 2.45e-12;
5251 ctl->oh_chem[1] = 1775;
5252 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5253 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5254 } else if (strcasecmp(ctl->species, "CO") == 0) {
5255 ctl->molmass = 28.01;
5256 ctl->oh_chem_reaction = 3;
5257 ctl->oh_chem[0] = 6.9e-33;
5258 ctl->oh_chem[1] = 2.1;
5259 ctl->oh_chem[2] = 1.1e-12;
5260 ctl->oh_chem[3] = -1.3;
5261 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5262 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5263 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5264 ctl->molmass = 44.009;
5265 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5266 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5267 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5268 ctl->molmass = 18.01528;
5269 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5270 ctl->molmass = 44.013;
5271 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5272 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5273 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5274 ctl->molmass = 17.031;
5275 ctl->oh_chem_reaction = 2;
5276 ctl->oh_chem[0] = 1.7e-12;
5277 ctl->oh_chem[1] = 710;
5278 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5279 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5280 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5281 ctl->molmass = 63.012;
5282 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5283 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5284 } else if (strcasecmp(ctl->species, "NO") == 0) {
5285 ctl->molmass = 30.006;
5286 ctl->oh_chem_reaction = 3;
5287 ctl->oh_chem[0] = 7.1e-31;
5288 ctl->oh_chem[1] = 2.6;
5289 ctl->oh_chem[2] = 3.6e-11;
5290 ctl->oh_chem[3] = 0.1;
5291 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5292 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5293 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5294 ctl->molmass = 46.005;
5295 ctl->oh_chem_reaction = 3;
5296 ctl->oh_chem[0] = 1.8e-30;
5297 ctl->oh_chem[1] = 3.0;
5298 ctl->oh_chem[2] = 2.8e-11;
5299 ctl->oh_chem[3] = 0.0;
5300 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5301 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5302 } else if (strcasecmp(ctl->species, "O3") == 0) {
5303 ctl->molmass = 47.997;
5304 ctl->oh_chem_reaction = 2;
5305 ctl->oh_chem[0] = 1.7e-12;
5306 ctl->oh_chem[1] = 940;
5307 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5308 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5309 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5310 ctl->molmass = 146.048;
5311 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5312 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5313 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5314 ctl->molmass = 64.066;
5315 ctl->oh_chem_reaction = 3;
5316 ctl->oh_chem[0] = 2.9e-31;
5317 ctl->oh_chem[1] = 4.1;
5318 ctl->oh_chem[2] = 1.7e-12;
5319 ctl->oh_chem[3] = -0.2;
5320 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5321 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5322 }
5323
5324 /* Molar mass... */
5325 char defstr[LEN];
5326 sprintf(defstr, "%g", ctl->molmass);
5327 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5328
5329 /* OH chemistry... */
5330 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5331 ctl->oh_chem_reaction =
5332 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5333 NULL);
5334 for (int ip = 0; ip < 4; ip++) {
5335 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5336 ctl->oh_chem[ip] =
5337 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5338 }
5339 ctl->oh_chem_beta =
5340 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5341
5342 /* H2O2 chemistry... */
5343 ctl->h2o2_chem_reaction =
5344 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5345
5346 /* KPP chemistry... */
5347 ctl->kpp_chem =
5348 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5349 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5350
5351 /* First order tracer chemistry... */
5352 ctl->tracer_chem =
5353 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5354
5355 /* Wet deposition... */
5356 for (int ip = 0; ip < 3; ip++) {
5357 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5358 ctl->wet_depo_ic_h[ip] =
5359 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5360 }
5361 for (int ip = 0; ip < 1; ip++) {
5362 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5363 ctl->wet_depo_bc_h[ip] =
5364 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5365 }
5366 ctl->wet_depo_ic_a =
5367 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5368 ctl->wet_depo_ic_b =
5369 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5370 ctl->wet_depo_bc_a =
5371 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5372 ctl->wet_depo_bc_b =
5373 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5374 ctl->wet_depo_pre[0] =
5375 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5376 ctl->wet_depo_pre[1] =
5377 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5379 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5381 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5382
5383 /* Dry deposition... */
5384 ctl->dry_depo_vdep =
5385 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5386 ctl->dry_depo_dp =
5387 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5388
5389 /* Climatological data... */
5390 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5391 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5392 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5393 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5394 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5395 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5396 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5397 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5398 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5399 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5400 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5401 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5402 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5403 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5404 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5405 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5406 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5407 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5408 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5409 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5410 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5411 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5412
5413 /* Mixing... */
5414 ctl->mixing_dt =
5415 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5416 ctl->mixing_trop =
5417 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5418 ctl->mixing_strat =
5419 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5420 ctl->mixing_z0 =
5421 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5422 ctl->mixing_z1 =
5423 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5424 ctl->mixing_nz =
5425 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5426 ctl->mixing_lon0 =
5427 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5428 ctl->mixing_lon1 =
5429 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5430 ctl->mixing_nx =
5431 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5432 ctl->mixing_lat0 =
5433 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5434 ctl->mixing_lat1 =
5435 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5436 ctl->mixing_ny =
5437 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5438
5439 /* Chemistry grid... */
5440 ctl->chemgrid_z0 =
5441 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5442 ctl->chemgrid_z1 =
5443 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5444 ctl->chemgrid_nz =
5445 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5446 ctl->chemgrid_lon0 =
5447 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5448 ctl->chemgrid_lon1 =
5449 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5450 ctl->chemgrid_nx =
5451 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5452 ctl->chemgrid_lat0 =
5453 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5454 ctl->chemgrid_lat1 =
5455 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5456 ctl->chemgrid_ny =
5457 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5458
5459 /* Exponential decay... */
5460 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5461 ctl->tdec_strat
5462 = scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5463
5464 /* PSC analysis... */
5465 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5466 ctl->psc_hno3 =
5467 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5468
5469 /* Output of atmospheric data... */
5470 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5471 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5472 ctl->atm_dt_out =
5473 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5474 ctl->atm_filter =
5475 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5476 ctl->atm_stride =
5477 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5478 ctl->atm_type =
5479 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
5480 ctl->atm_type_out =
5481 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
5482 if (ctl->atm_type_out == -1)
5483 ctl->atm_type_out = ctl->atm_type;
5484 ctl->atm_nc_level =
5485 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
5486 for (int iq = 0; iq < ctl->nq; iq++)
5487 ctl->atm_nc_quant[iq] =
5488 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
5489 ctl->obs_type =
5490 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
5491
5492 /* Output of CSI data... */
5493 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
5494 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
5495 ctl->csi_dt_out =
5496 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
5497 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
5498 ctl->csi_obsmin =
5499 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
5500 ctl->csi_modmin =
5501 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
5502 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
5503 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
5504 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
5505 ctl->csi_lon0 =
5506 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
5507 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
5508 ctl->csi_nx =
5509 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
5510 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
5511 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
5512 ctl->csi_ny =
5513 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
5514
5515 /* Output of ensemble data... */
5516 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
5517 ctl->ens_dt_out =
5518 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
5519
5520 /* Output of grid data... */
5521 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
5522 ctl->grid_basename);
5523 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
5524 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
5525 ctl->grid_dt_out =
5526 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
5527 ctl->grid_sparse =
5528 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
5529 ctl->grid_nc_level =
5530 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
5531 for (int iq = 0; iq < ctl->nq; iq++)
5532 ctl->grid_nc_quant[iq] =
5533 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
5534 ctl->grid_stddev =
5535 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
5536 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
5537 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
5538 ctl->grid_nz =
5539 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
5540 ctl->grid_lon0 =
5541 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
5542 ctl->grid_lon1 =
5543 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
5544 ctl->grid_nx =
5545 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
5546 ctl->grid_lat0 =
5547 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
5548 ctl->grid_lat1 =
5549 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
5550 ctl->grid_ny =
5551 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
5552 ctl->grid_type =
5553 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
5554
5555 /* Output of profile data... */
5556 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
5557 ctl->prof_basename);
5558 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
5559 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
5560 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
5561 ctl->prof_nz =
5562 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
5563 ctl->prof_lon0 =
5564 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
5565 ctl->prof_lon1 =
5566 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
5567 ctl->prof_nx =
5568 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
5569 ctl->prof_lat0 =
5570 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
5571 ctl->prof_lat1 =
5572 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
5573 ctl->prof_ny =
5574 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
5575
5576 /* Output of sample data... */
5577 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
5578 ctl->sample_basename);
5579 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
5580 ctl->sample_kernel);
5581 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
5582 ctl->sample_obsfile);
5583 ctl->sample_dx =
5584 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
5585 ctl->sample_dz =
5586 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
5587
5588 /* Output of station data... */
5589 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
5590 ctl->stat_basename);
5591 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
5592 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
5593 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
5594 ctl->stat_t0 =
5595 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
5596 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
5597
5598 /* Output of VTK data... */
5599 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
5600 ctl->vtk_dt_out =
5601 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
5602 ctl->vtk_stride =
5603 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
5604 ctl->vtk_scale =
5605 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
5606 ctl->vtk_offset =
5607 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
5608 ctl->vtk_sphere =
5609 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
5610}
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:1909
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:8098
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:246
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1508
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3000
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2276
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:2964
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:2931
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2309
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:2940
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2255
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2892
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2288
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:2934
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2297
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:2955
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2264
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3078
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2626
double stat_r
Search radius around station [km].
Definition: mptrac.h:3084
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:2958
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3108
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2594
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2285
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2363
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3027
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3003
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2613
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2327
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2390
char species[LEN]
Species.
Definition: mptrac.h:2714
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:2949
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:2961
int met_pbl
Planetary boundary layer data (0=file, 1=Richardson, 2=theta).
Definition: mptrac.h:2591
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2279
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:2988
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3006
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3018
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2219
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2306
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3009
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2333
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2610
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3063
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2384
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2582
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:2979
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2231
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2375
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3090
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:2925
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3024
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:2952
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2237
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:2994
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2360
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2579
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2216
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3030
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2222
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3033
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:2928
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2588
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:2937
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:2976
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3036
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2270
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2604
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3042
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2201
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2619
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2393
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2330
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:2946
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3087
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:2910
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2840
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:2922
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2228
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3096
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2669
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3066
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2321
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:2973
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2249
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2369
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2597
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2381
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2843
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2252
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3105
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2267
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2324
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2273
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3051
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2372
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2261
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3072
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:2919
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:2991
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2225
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3012
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2889
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2240
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2300
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3039
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2258
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:2898
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2837
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:2967
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:2943
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2387
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3081
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3015
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2312
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2318
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:2997
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:2970
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3060
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:2901
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2585
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2895
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3057
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2879
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3045
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2294
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2342
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2357
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3054
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2315
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2882
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3048
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2834
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2916
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:2985
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3093
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2243
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2198
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2762
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3102
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2396
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2234
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2913
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2366
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2195
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2607
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2282
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2186
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3069
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3099
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3075
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3021
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2246
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2291
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2303
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:2982
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2399
Here is the call graph for this function:

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

5618 {
5619
5620 /* Write info... */
5621 LOG(1, "Read kernel function: %s", filename);
5622
5623 /* Open file... */
5624 FILE *in;
5625 if (!(in = fopen(filename, "r")))
5626 ERRMSG("Cannot open file!");
5627
5628 /* Read data... */
5629 char line[LEN];
5630 int n = 0;
5631 while (fgets(line, LEN, in))
5632 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
5633 if (n > 0 && kz[n] < kz[n - 1])
5634 ERRMSG("Height levels must be ascending!");
5635 if ((++n) >= EP)
5636 ERRMSG("Too many height levels!");
5637 }
5638
5639 /* Close file... */
5640 fclose(in);
5641
5642 /* Check number of data points... */
5643 *nk = n;
5644 if (n < 2)
5645 ERRMSG("Not enough height levels!");
5646
5647 /* Normalize kernel function... */
5648 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
5649 for (int iz = 0; iz < n; iz++)
5650 kw[iz] /= kmax;
5651}

◆ read_met()

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

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

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

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

Definition at line 5655 of file mptrac.c.

5659 {
5660
5661 /* Write info... */
5662 LOG(1, "Read meteo data: %s", filename);
5663
5664 /* Set rank... */
5665 int rank = 0;
5666#ifdef MPI
5667 if (ctl->met_mpi_share)
5668 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5669#endif
5670
5671 /* Check rank... */
5672 if (!ctl->met_mpi_share || rank == 0) {
5673
5674 /* Read netCDF data... */
5675 if (ctl->met_type == 0) {
5676 if (read_met_nc(filename, ctl, clim, met) != 1)
5677 return 0;
5678 }
5679
5680 /* Read binary data... */
5681 else if (ctl->met_type >= 1 && ctl->met_type <= 5) {
5682 if (read_met_bin(filename, ctl, met) != 1)
5683 return 0;
5684 }
5685
5686 /* Not implemented... */
5687 else
5688 ERRMSG("MET_TYPE not implemented!");
5689 }
5690
5691 /* Broadcast data via MPI... */
5692#ifdef MPI
5693 if (ctl->met_mpi_share) {
5694
5695 /* Set timer... */
5696 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
5697 LOG(2, "Broadcast data on rank %d...", rank);
5698
5699 /* Broadcast... */
5700 broadcast_large_data(met, sizeof(met_t));
5701 }
5702#endif
5703
5704 /* Return success... */
5705 return 1;
5706}
int read_met_bin(const char *filename, ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:5710
int read_met_nc(const char *filename, ctl_t *ctl, clim_t *clim, met_t *met)
Reads meteorological data from a NetCDF file and processes it.
Definition: mptrac.c:6794
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:

◆ read_met_bin()

int read_met_bin ( const char *  filename,
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 5710 of file mptrac.c.

5713 {
5714
5715 FILE *in;
5716
5717 double r;
5718
5719 int year, mon, day, hour, min, sec;
5720
5721 /* Set timer... */
5722 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
5723
5724 /* Open file... */
5725 if (!(in = fopen(filename, "r"))) {
5726 WARN("Cannot open file!");
5727 return 0;
5728 }
5729
5730 /* Check type of binary data... */
5731 int met_type;
5732 FREAD(&met_type, int,
5733 1,
5734 in);
5735 if (met_type != ctl->met_type)
5736 ERRMSG("Wrong MET_TYPE of binary data!");
5737
5738 /* Check version of binary data... */
5739 int version;
5740 FREAD(&version, int,
5741 1,
5742 in);
5743 if (version != 100 && version != 101 && version != 102)
5744 ERRMSG("Wrong version of binary data!");
5745
5746 /* Read time... */
5747 FREAD(&met->time, double,
5748 1,
5749 in);
5750 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
5751 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
5752 met->time, year, mon, day, hour, min);
5753 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
5754 || day < 1 || day > 31 || hour < 0 || hour > 23)
5755 ERRMSG("Error while reading time!");
5756
5757 /* Read dimensions... */
5758 FREAD(&met->nx, int,
5759 1,
5760 in);
5761 LOG(2, "Number of longitudes: %d", met->nx);
5762 if (met->nx < 2 || met->nx > EX)
5763 ERRMSG("Number of longitudes out of range!");
5764
5765 FREAD(&met->ny, int,
5766 1,
5767 in);
5768 LOG(2, "Number of latitudes: %d", met->ny);
5769 if (met->ny < 2 || met->ny > EY)
5770 ERRMSG("Number of latitudes out of range!");
5771
5772 FREAD(&met->np, int,
5773 1,
5774 in);
5775 LOG(2, "Number of levels: %d", met->np);
5776 if (met->np < 2 || met->np > EP)
5777 ERRMSG("Number of levels out of range!");
5778
5779 /* Read grid... */
5780 FREAD(met->lon, double,
5781 (size_t) met->nx,
5782 in);
5783 LOG(2, "Longitudes: %g, %g ... %g deg",
5784 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
5785
5786 FREAD(met->lat, double,
5787 (size_t) met->ny,
5788 in);
5789 LOG(2, "Latitudes: %g, %g ... %g deg",
5790 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
5791
5792 FREAD(met->p, double,
5793 (size_t) met->np,
5794 in);
5795 LOG(2, "Altitude levels: %g, %g ... %g km",
5796 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
5797 LOG(2, "Pressure levels: %g, %g ... %g hPa",
5798 met->p[0], met->p[1], met->p[met->np - 1]);
5799
5800 /* Read surface data... */
5801 read_met_bin_2d(in, met, met->ps, "PS");
5802 read_met_bin_2d(in, met, met->ts, "TS");
5803 read_met_bin_2d(in, met, met->zs, "ZS");
5804 read_met_bin_2d(in, met, met->us, "US");
5805 read_met_bin_2d(in, met, met->vs, "VS");
5806 if (version >= 101) {
5807 read_met_bin_2d(in, met, met->lsm, "LSM");
5808 read_met_bin_2d(in, met, met->sst, "SST");
5809 }
5810 read_met_bin_2d(in, met, met->pbl, "PBL");
5811 read_met_bin_2d(in, met, met->pt, "PT");
5812 read_met_bin_2d(in, met, met->tt, "TT");
5813 read_met_bin_2d(in, met, met->zt, "ZT");
5814 read_met_bin_2d(in, met, met->h2ot, "H2OT");
5815 read_met_bin_2d(in, met, met->pct, "PCT");
5816 read_met_bin_2d(in, met, met->pcb, "PCB");
5817 read_met_bin_2d(in, met, met->cl, "CL");
5818 read_met_bin_2d(in, met, met->plcl, "PLCL");
5819 read_met_bin_2d(in, met, met->plfc, "PLFC");
5820 read_met_bin_2d(in, met, met->pel, "PEL");
5821 read_met_bin_2d(in, met, met->cape, "CAPE");
5822 read_met_bin_2d(in, met, met->cin, "CIN");
5823
5824 /* Read level data... */
5825 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
5826 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
5827 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
5828 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
5829 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
5830 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
5831 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
5832 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
5833 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
5834 if (version >= 102)
5835 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
5836 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
5837 if (version >= 102)
5838 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
5839 if (version >= 101)
5840 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
5841
5842 /* Read final flag... */
5843 int final;
5844 FREAD(&final, int,
5845 1,
5846 in);
5847 if (final != 999)
5848 ERRMSG("Error while reading binary data!");
5849
5850 /* Close file... */
5851 fclose(in);
5852
5853 /* Return success... */
5854 return 1;
5855}
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:5859
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:5888
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:269
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3401
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3389
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3461
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3425
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3407
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3458
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3380
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3470
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3374
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3410
float pel[EX][EY]
Pressure at equilibrium level [hPa].
Definition: mptrac.h:3422
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3428
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3416
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3398
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3392
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3383
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3386
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3464
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3404
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3449
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3413
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3419
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3467
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 5859 of file mptrac.c.

5863 {
5864
5865 float *help;
5866
5867 /* Allocate... */
5868 ALLOC(help, float,
5869 EX * EY);
5870
5871 /* Read uncompressed... */
5872 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
5873 FREAD(help, float,
5874 (size_t) (met->nx * met->ny),
5875 in);
5876
5877 /* Copy data... */
5878 for (int ix = 0; ix < met->nx; ix++)
5879 for (int iy = 0; iy < met->ny; iy++)
5880 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
5881
5882 /* Free... */
5883 free(help);
5884}
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:370

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

5895 {
5896
5897 float *help;
5898
5899 /* Allocate... */
5900 ALLOC(help, float,
5901 EX * EY * EP);
5902
5903 /* Read uncompressed data... */
5904 if (ctl->met_type == 1) {
5905 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
5906 FREAD(help, float,
5907 (size_t) (met->nx * met->ny * met->np),
5908 in);
5909 }
5910
5911 /* Read packed data... */
5912 else if (ctl->met_type == 2)
5913 compress_pck(varname, help, (size_t) (met->ny * met->nx),
5914 (size_t) met->np, 1, in);
5915
5916 /* Read zfp data... */
5917 else if (ctl->met_type == 3) {
5918#ifdef ZFP
5919 int precision;
5920 FREAD(&precision, int,
5921 1,
5922 in);
5923
5924 double tolerance;
5925 FREAD(&tolerance, double,
5926 1,
5927 in);
5928
5929 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
5930 tolerance, 1, in);
5931#else
5932 ERRMSG("MPTRAC was compiled without zfp compression!");
5933#endif
5934 }
5935
5936 /* Read zstd data... */
5937 else if (ctl->met_type == 4) {
5938#ifdef ZSTD
5939 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
5940 in);
5941#else
5942 ERRMSG("MPTRAC was compiled without zstd compression!");
5943#endif
5944 }
5945
5946 /* Read cmultiscale data... */
5947 else if (ctl->met_type == 5) {
5948#ifdef CMS
5949 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
5950 (size_t) met->np, 1, in);
5951#else
5952 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
5953#endif
5954 }
5955
5956 /* Copy data... */
5957#pragma omp parallel for default(shared) collapse(2)
5958 for (int ix = 0; ix < met->nx; ix++)
5959 for (int iy = 0; iy < met->ny; iy++)
5960 for (int ip = 0; ip < met->np; ip++) {
5961 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
5962 if (var[ix][iy][ip] < bound_min)
5963 var[ix][iy][ip] = bound_min;
5964 else if (var[ix][iy][ip] > bound_max)
5965 var[ix][iy][ip] = bound_max;
5966 }
5967
5968 /* Free... */
5969 free(help);
5970}
void compress_pck(const char *varname, float *array, const size_t nxy, const size_t nz, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats.
Definition: mptrac.c:657
void compress_cms(const ctl_t *ctl, const char *varname, float *array, const size_t nx, const size_t ny, const size_t np, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using a custom multiscale compression algorithm.
void compress_zfp(const char *varname, float *array, const int nx, const int ny, const int nz, const int precision, const double tolerance, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
void compress_zstd(const char *varname, float *array, const size_t n, const int decompress, FILE *inout)
Compresses or decompresses an array of floats using the Zstandard (ZSTD) library.
Here is the call graph for this function:

◆ read_met_cape()

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

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

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

Parameters
climA pointer to a structure containing climatological data.
metA pointer to a structure containing meteorological data.

The function performs the following steps:

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

Definition at line 5974 of file mptrac.c.

5977 {
5978
5979 /* Check parameters... */
5980 if (ctl->met_cape != 1)
5981 return;
5982
5983 /* Set timer... */
5984 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
5985 LOG(2, "Calculate CAPE...");
5986
5987 /* Vertical spacing (about 100 m)... */
5988 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
5989
5990 /* Loop over columns... */
5991#pragma omp parallel for default(shared) collapse(2)
5992 for (int ix = 0; ix < met->nx; ix++)
5993 for (int iy = 0; iy < met->ny; iy++) {
5994
5995 /* Get potential temperature and water vapor at lowest 50 hPa... */
5996 int n = 0;
5997 double h2o = 0, t, theta = 0;
5998 double pbot = MIN(met->ps[ix][iy], met->p[0]);
5999 double ptop = pbot - 50.;
6000 for (int ip = 0; ip < met->np; ip++) {
6001 if (met->p[ip] <= pbot) {
6002 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
6003 h2o += met->h2o[ix][iy][ip];
6004 n++;
6005 }
6006 if (met->p[ip] < ptop && n > 0)
6007 break;
6008 }
6009 theta /= n;
6010 h2o /= n;
6011
6012 /* Cannot compute anything if water vapor is missing... */
6013 met->plcl[ix][iy] = NAN;
6014 met->plfc[ix][iy] = NAN;
6015 met->pel[ix][iy] = NAN;
6016 met->cape[ix][iy] = NAN;
6017 met->cin[ix][iy] = NAN;
6018 if (h2o <= 0)
6019 continue;
6020
6021 /* Find lifted condensation level (LCL)... */
6022 ptop = P(20.);
6023 pbot = met->ps[ix][iy];
6024 do {
6025 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
6026 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
6027 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
6028 ptop = met->plcl[ix][iy];
6029 else
6030 pbot = met->plcl[ix][iy];
6031 } while (pbot - ptop > 0.1);
6032
6033 /* Calculate CIN up to LCL... */
6035 double dcape, dz, h2o_env, t_env;
6036 double p = met->ps[ix][iy];
6037 met->cape[ix][iy] = met->cin[ix][iy] = 0;
6038 do {
6039 dz = dz0 * TVIRT(t, h2o);
6040 p /= pfac;
6041 t = theta / pow(1000. / p, 0.286);
6042 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6043 &t_env, ci, cw, 1);
6044 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6045 &h2o_env, ci, cw, 0);
6046 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6047 TVIRT(t_env, h2o_env) * dz;
6048 if (dcape < 0)
6049 met->cin[ix][iy] += fabsf((float) dcape);
6050 } while (p > met->plcl[ix][iy]);
6051
6052 /* Calculate level of free convection (LFC), equilibrium level (EL),
6053 and convective available potential energy (CAPE)... */
6054 dcape = 0;
6055 p = met->plcl[ix][iy];
6056 t = theta / pow(1000. / p, 0.286);
6057 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
6058 do {
6059 dz = dz0 * TVIRT(t, h2o);
6060 p /= pfac;
6061 t -= lapse_rate(t, h2o) * dz;
6062 double psat = PSAT(t);
6063 h2o = psat / (p - (1. - EPS) * psat);
6064 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6065 &t_env, ci, cw, 1);
6066 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6067 &h2o_env, ci, cw, 0);
6068 double dcape_old = dcape;
6069 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6070 TVIRT(t_env, h2o_env) * dz;
6071 if (dcape > 0) {
6072 met->cape[ix][iy] += (float) dcape;
6073 if (!isfinite(met->plfc[ix][iy]))
6074 met->plfc[ix][iy] = (float) p;
6075 } else if (dcape_old > 0)
6076 met->pel[ix][iy] = (float) p;
6077 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
6078 met->cin[ix][iy] += fabsf((float) dcape);
6079 } while (p > ptop);
6080
6081 /* Check results... */
6082 if (!isfinite(met->plfc[ix][iy]))
6083 met->cin[ix][iy] = NAN;
6084 }
6085}
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:200
Here is the call graph for this function:

◆ read_met_cloud()

void read_met_cloud ( met_t met)

Calculates cloud-related variables for each grid point.

This function calculates cloud-related variables, such as cloud cover, cloud top pressure, cloud bottom pressure, and total cloud water content, based on the provided meteorological data.

Parameters
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the calculation time.
  • Initializes variables and constants required for the computation.
  • Iterates over each grid point in parallel using OpenMP.
  • Determines cloud-related variables based on thresholds for liquid water content (LWC), rain water content (RWC), ice water content (IWC) and snow water content (SWC).
  • Calculates cloud cover, cloud top pressure, cloud bottom pressure, and total cloud water content for each grid point.
  • Updates the corresponding fields in the meteorological data structure.
Note
The function utilizes OpenMP for parallelization to enhance performance by distributing the computation across multiple threads.
Author
Lars Hoffmann

Definition at line 6089 of file mptrac.c.

6090 {
6091
6092 /* Set timer... */
6093 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
6094 LOG(2, "Calculate cloud data...");
6095
6096 /* Thresholds for cloud detection... */
6097 const double ccmin = 0.01, cwmin = 1e-6;
6098
6099 /* Loop over columns... */
6100#pragma omp parallel for default(shared) collapse(2)
6101 for (int ix = 0; ix < met->nx; ix++)
6102 for (int iy = 0; iy < met->ny; iy++) {
6103
6104 /* Init... */
6105 met->pct[ix][iy] = NAN;
6106 met->pcb[ix][iy] = NAN;
6107 met->cl[ix][iy] = 0;
6108
6109 /* Loop over pressure levels... */
6110 for (int ip = 0; ip < met->np - 1; ip++) {
6111
6112 /* Check pressure... */
6113 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
6114 continue;
6115
6116 /* Check ice water and liquid water content... */
6117 if (met->cc[ix][iy][ip] > ccmin
6118 && (met->iwc[ix][iy][ip] > cwmin
6119 || met->rwc[ix][iy][ip] > cwmin
6120 || met->lwc[ix][iy][ip] > cwmin
6121 || met->swc[ix][iy][ip] > cwmin)) {
6122
6123 /* Get cloud top pressure ... */
6124 met->pct[ix][iy]
6125 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
6126
6127 /* Get cloud bottom pressure ... */
6128 if (!isfinite(met->pcb[ix][iy]))
6129 met->pcb[ix][iy]
6130 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
6131 }
6132
6133 /* Get cloud water... */
6134 met->cl[ix][iy] += (float)
6135 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
6136 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
6137 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
6138 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
6139 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
6140 }
6141 }
6142}

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

6148 {
6149
6150 met_t *help;
6151
6152 /* Check parameters... */
6153 if (ctl->met_detrend <= 0)
6154 return;
6155
6156 /* Set timer... */
6157 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
6158 LOG(2, "Detrend meteo data...");
6159
6160 /* Allocate... */
6161 ALLOC(help, met_t, 1);
6162
6163 /* Calculate standard deviation... */
6164 const double sigma = ctl->met_detrend / 2.355;
6165 const double tssq = 2. * SQR(sigma);
6166
6167 /* Calculate box size in latitude... */
6168 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
6169 sy = MIN(MAX(1, sy), met->ny / 2);
6170
6171 /* Calculate background... */
6172#pragma omp parallel for default(shared) collapse(2)
6173 for (int ix = 0; ix < met->nx; ix++) {
6174 for (int iy = 0; iy < met->ny; iy++) {
6175
6176 /* Calculate Cartesian coordinates... */
6177 double x0[3];
6178 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
6179
6180 /* Calculate box size in longitude... */
6181 int sx =
6182 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
6183 fabs(met->lon[1] - met->lon[0]));
6184 sx = MIN(MAX(1, sx), met->nx / 2);
6185
6186 /* Init... */
6187 float wsum = 0;
6188 for (int ip = 0; ip < met->np; ip++) {
6189 help->t[ix][iy][ip] = 0;
6190 help->u[ix][iy][ip] = 0;
6191 help->v[ix][iy][ip] = 0;
6192 help->w[ix][iy][ip] = 0;
6193 }
6194
6195 /* Loop over neighboring grid points... */
6196 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
6197 int ix3 = ix2;
6198 if (ix3 < 0)
6199 ix3 += met->nx;
6200 else if (ix3 >= met->nx)
6201 ix3 -= met->nx;
6202 for (int iy2 = MAX(iy - sy, 0);
6203 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
6204
6205 /* Calculate Cartesian coordinates... */
6206 double x1[3];
6207 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
6208
6209 /* Calculate weighting factor... */
6210 const float w = (float) exp(-DIST2(x0, x1) / tssq);
6211
6212 /* Add data... */
6213 wsum += w;
6214 for (int ip = 0; ip < met->np; ip++) {
6215 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
6216 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
6217 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
6218 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
6219 }
6220 }
6221 }
6222
6223 /* Normalize... */
6224 for (int ip = 0; ip < met->np; ip++) {
6225 help->t[ix][iy][ip] /= wsum;
6226 help->u[ix][iy][ip] /= wsum;
6227 help->v[ix][iy][ip] /= wsum;
6228 help->w[ix][iy][ip] /= wsum;
6229 }
6230 }
6231 }
6232
6233 /* Subtract background... */
6234#pragma omp parallel for default(shared) collapse(3)
6235 for (int ix = 0; ix < met->nx; ix++)
6236 for (int iy = 0; iy < met->ny; iy++)
6237 for (int ip = 0; ip < met->np; ip++) {
6238 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
6239 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
6240 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
6241 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
6242 }
6243
6244 /* Free... */
6245 free(help);
6246}
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:986
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:588
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2570
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 6250 of file mptrac.c.

6251 {
6252
6253 /* Set timer... */
6254 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
6255 LOG(2, "Extrapolate meteo data...");
6256
6257 /* Loop over columns... */
6258#pragma omp parallel for default(shared) collapse(2)
6259 for (int ix = 0; ix < met->nx; ix++)
6260 for (int iy = 0; iy < met->ny; iy++) {
6261
6262 /* Find lowest valid data point... */
6263 int ip0;
6264 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
6265 if (!isfinite(met->t[ix][iy][ip0])
6266 || !isfinite(met->u[ix][iy][ip0])
6267 || !isfinite(met->v[ix][iy][ip0])
6268 || !isfinite(met->w[ix][iy][ip0]))
6269 break;
6270
6271 /* Extrapolate... */
6272 for (int ip = ip0; ip >= 0; ip--) {
6273 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
6274 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
6275 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
6276 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
6277 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
6278 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
6279 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
6280 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
6281 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
6282 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
6283 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
6284 }
6285 }
6286}

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

6292 {
6293
6294 float *help;
6295
6296 double logp[EP];
6297
6298 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
6299
6300 /* Set timer... */
6301 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
6302 LOG(2, "Calculate geopotential heights...");
6303
6304 /* Allocate... */
6305 ALLOC(help, float,
6306 EX * EY * EP);
6307
6308 /* Calculate log pressure... */
6309#pragma omp parallel for default(shared)
6310 for (int ip = 0; ip < met->np; ip++)
6311 logp[ip] = log(met->p[ip]);
6312
6313 /* Apply hydrostatic equation to calculate geopotential heights... */
6314#pragma omp parallel for default(shared) collapse(2)
6315 for (int ix = 0; ix < met->nx; ix++)
6316 for (int iy = 0; iy < met->ny; iy++) {
6317
6318 /* Get surface height and pressure... */
6319 const double zs = met->zs[ix][iy];
6320 const double lnps = log(met->ps[ix][iy]);
6321
6322 /* Get temperature and water vapor at the surface... */
6323 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
6324 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
6325 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
6326 const double h2os =
6327 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
6328 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
6329
6330 /* Upper part of profile... */
6331 met->z[ix][iy][ip0 + 1]
6332 = (float) (zs +
6333 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
6334 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
6335 for (int ip = ip0 + 2; ip < met->np; ip++)
6336 met->z[ix][iy][ip]
6337 = (float) (met->z[ix][iy][ip - 1] +
6338 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
6339 met->h2o[ix][iy][ip - 1], logp[ip],
6340 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
6341
6342 /* Lower part of profile... */
6343 met->z[ix][iy][ip0]
6344 = (float) (zs +
6345 ZDIFF(lnps, ts, h2os, logp[ip0],
6346 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
6347 for (int ip = ip0 - 1; ip >= 0; ip--)
6348 met->z[ix][iy][ip]
6349 = (float) (met->z[ix][iy][ip + 1] +
6350 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
6351 met->h2o[ix][iy][ip + 1], logp[ip],
6352 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
6353 }
6354
6355 /* Check control parameters... */
6356 if (dx == 0 || dy == 0)
6357 return;
6358
6359 /* Default smoothing parameters... */
6360 if (dx < 0 || dy < 0) {
6361 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
6362 dx = 3;
6363 dy = 2;
6364 } else {
6365 dx = 6;
6366 dy = 4;
6367 }
6368 }
6369
6370 /* Calculate weights for smoothing... */
6371 float ws[dx + 1][dy + 1];
6372#pragma omp parallel for default(shared) collapse(2)
6373 for (int ix = 0; ix <= dx; ix++)
6374 for (int iy = 0; iy < dy; iy++)
6375 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
6376 * (1.0f - (float) iy / (float) dy);
6377
6378 /* Copy data... */
6379#pragma omp parallel for default(shared) collapse(3)
6380 for (int ix = 0; ix < met->nx; ix++)
6381 for (int iy = 0; iy < met->ny; iy++)
6382 for (int ip = 0; ip < met->np; ip++)
6383 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
6384
6385 /* Horizontal smoothing... */
6386#pragma omp parallel for default(shared) collapse(3)
6387 for (int ip = 0; ip < met->np; ip++)
6388 for (int ix = 0; ix < met->nx; ix++)
6389 for (int iy = 0; iy < met->ny; iy++) {
6390 float res = 0, wsum = 0;
6391 int iy0 = MAX(iy - dy + 1, 0);
6392 int iy1 = MIN(iy + dy - 1, met->ny - 1);
6393 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
6394 int ix3 = ix2;
6395 if (ix3 < 0)
6396 ix3 += met->nx;
6397 else if (ix3 >= met->nx)
6398 ix3 -= met->nx;
6399 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
6400 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
6401 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
6402 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
6403 wsum += w;
6404 }
6405 }
6406 if (wsum > 0)
6407 met->z[ix][iy][ip] = res / wsum;
6408 else
6409 met->z[ix][iy][ip] = NAN;
6410 }
6411
6412 /* Free... */
6413 free(help);
6414}
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1757
Here is the call graph for this function:

◆ read_met_grid()

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

Reads meteorological grid information from a NetCDF file.

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

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

The function performs the following steps:

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

Definition at line 6418 of file mptrac.c.

6422 {
6423
6424 char levname[LEN], tstr[10];
6425
6426 double rtime = 0, r, r2;
6427
6428 int varid, year2, mon2, day2, hour2, min2, sec2,
6429 year, mon, day, hour, min, sec;
6430
6431 size_t np;
6432
6433 /* Set timer... */
6434 SELECT_TIMER("READ_MET_GRID", "INPUT", NVTX_READ);
6435 LOG(2, "Read meteo grid information...");
6436
6437 /* MPTRAC meteo files... */
6438 if (ctl->met_clams == 0) {
6439
6440 /* Get time from filename... */
6441 met->time = time_from_filename(filename, 16);
6442
6443 /* Check time information from data file... */
6444 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
6445 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
6446 NC(nc_get_var_double(ncid, varid, &rtime));
6447 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
6448 WARN("Time information in meteo file does not match filename!");
6449 } else
6450 WARN("Time information in meteo file is missing!");
6451 }
6452
6453 /* CLaMS meteo files... */
6454 else {
6455
6456 /* Read time from file... */
6457 NC_GET_DOUBLE("time", &rtime, 0);
6458
6459 /* Get time from filename (considering the century)... */
6460 if (rtime < 0)
6461 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
6462 else
6463 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
6464 year = atoi(tstr);
6465 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
6466 mon = atoi(tstr);
6467 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
6468 day = atoi(tstr);
6469 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
6470 hour = atoi(tstr);
6471 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
6472 }
6473
6474 /* Check time... */
6475 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
6476 || day < 1 || day > 31 || hour < 0 || hour > 23)
6477 ERRMSG("Cannot read time from filename!");
6478 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
6479 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
6480 met->time, year2, mon2, day2, hour2, min2);
6481
6482 /* Get grid dimensions... */
6483 NC_INQ_DIM("lon", &met->nx, 2, EX);
6484 LOG(2, "Number of longitudes: %d", met->nx);
6485
6486 NC_INQ_DIM("lat", &met->ny, 2, EY);
6487 LOG(2, "Number of latitudes: %d", met->ny);
6488
6489 int dimid2;
6490 sprintf(levname, "lev");
6491 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
6492 sprintf(levname, "plev");
6493 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
6494 sprintf(levname, "hybrid");
6495
6496 NC_INQ_DIM(levname, &met->np, 1, EP);
6497 if (met->np == 1) {
6498 sprintf(levname, "lev_2");
6499 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR) {
6500 sprintf(levname, "plev");
6501 NC(nc_inq_dimid(ncid, levname, &dimid2));
6502 }
6503 NC(nc_inq_dimlen(ncid, dimid2, &np));
6504 met->np = (int) np;
6505 }
6506 LOG(2, "Number of levels: %d", met->np);
6507 if (met->np < 2 || met->np > EP)
6508 ERRMSG("Number of levels out of range!");
6509
6510 /* Read longitudes and latitudes... */
6511 NC_GET_DOUBLE("lon", met->lon, 1);
6512 LOG(2, "Longitudes: %g, %g ... %g deg",
6513 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
6514 NC_GET_DOUBLE("lat", met->lat, 1);
6515 LOG(2, "Latitudes: %g, %g ... %g deg",
6516 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
6517
6518 /* Read pressure levels... */
6519 if (ctl->met_np <= 0) {
6520 NC_GET_DOUBLE(levname, met->p, 1);
6521 for (int ip = 0; ip < met->np; ip++)
6522 met->p[ip] /= 100.;
6523 LOG(2, "Altitude levels: %g, %g ... %g km",
6524 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
6525 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6526 met->p[0], met->p[1], met->p[met->np - 1]);
6527 }
6528
6529 /* Read hybrid levels... */
6530 if (strcasecmp(levname, "hybrid") == 0)
6531 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
6532}
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:8314
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:8413
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3368
Here is the call graph for this function:

◆ read_met_levels()

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

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

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

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

The function performs the following steps:

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

Definition at line 6536 of file mptrac.c.

6539 {
6540
6541 /* Set timer... */
6542 SELECT_TIMER("READ_MET_LEVELS", "INPUT", NVTX_READ);
6543 LOG(2, "Read level data...");
6544
6545 /* Read temperature... */
6546 if (!read_met_nc_3d(ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
6547 ERRMSG("Cannot read temperature!");
6548
6549 /* Read horizontal wind and vertical velocity... */
6550 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
6551 ERRMSG("Cannot read zonal wind!");
6552 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
6553 ERRMSG("Cannot read meridional wind!");
6554 if (!read_met_nc_3d
6555 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
6556 WARN("Cannot read vertical velocity!");
6557
6558 /* Read water vapor... */
6559 if (!ctl->met_relhum) {
6560 if (!read_met_nc_3d
6561 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
6562 WARN("Cannot read specific humidity!");
6563 } else {
6564 if (!read_met_nc_3d
6565 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
6566 WARN("Cannot read relative humidity!");
6567#pragma omp parallel for default(shared) collapse(2)
6568 for (int ix = 0; ix < met->nx; ix++)
6569 for (int iy = 0; iy < met->ny; iy++)
6570 for (int ip = 0; ip < met->np; ip++) {
6571 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
6572 met->h2o[ix][iy][ip] =
6573 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
6574 }
6575 }
6576
6577 /* Read ozone... */
6578 if (!read_met_nc_3d
6579 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
6580 WARN("Cannot read ozone data!");
6581
6582 /* Read cloud data... */
6583 if (!read_met_nc_3d
6584 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
6585 WARN("Cannot read cloud liquid water content!");
6586 if (!read_met_nc_3d
6587 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
6588 WARN("Cannot read cloud rain water content!");
6589 if (!read_met_nc_3d
6590 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
6591 WARN("Cannot read cloud ice water content!");
6592 if (!read_met_nc_3d
6593 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
6594 WARN("Cannot read cloud snow water content!");
6595 if (!read_met_nc_3d(ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
6596 WARN("Cannot read cloud cover!");
6597
6598 /* Read zeta and zeta_dot... */
6599 if (!read_met_nc_3d
6600 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
6601 WARN("Cannot read ZETA!");
6602 if (!read_met_nc_3d
6603 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
6604 NULL, ctl, met, met->zeta_dotl, 0.00001157407f))
6605 WARN("Cannot read ZETA_DOT!");
6606
6607 /* Store velocities on model levels for diabatic advection... */
6608 if (ctl->met_vert_coord == 1) {
6609 for (int ix = 0; ix < met->nx; ix++)
6610 for (int iy = 0; iy < met->ny; iy++)
6611 for (int ip = 0; ip < met->np; ip++) {
6612 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
6613 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
6614 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
6615 }
6616
6617 /* Original number of vertical levels... */
6618 met->npl = met->np;
6619 }
6620
6621 /* Read pressure on model levels... */
6622 if (ctl->met_np > 0 || ctl->met_vert_coord == 1) {
6623
6624 /* Read data... */
6625 if (!read_met_nc_3d
6626 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl, 0.01f))
6627 if (!read_met_nc_3d
6628 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
6629 ERRMSG("Cannot read pressure on model levels!");
6630
6631 /* Check ordering of pressure levels... */
6632 for (int ix = 0; ix < met->nx; ix++)
6633 for (int iy = 0; iy < met->ny; iy++)
6634 for (int ip = 1; ip < met->np; ip++)
6635 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
6636 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
6637 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
6638 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
6639 ERRMSG("Pressure profiles are not monotonic!");
6640 }
6641
6642 /* Interpolate from model levels to pressure levels... */
6643 if (ctl->met_np > 0) {
6644
6645 /* Interpolate variables... */
6646 read_met_ml2pl(ctl, met, met->t, "T");
6647 read_met_ml2pl(ctl, met, met->u, "U");
6648 read_met_ml2pl(ctl, met, met->v, "V");
6649 read_met_ml2pl(ctl, met, met->w, "W");
6650 read_met_ml2pl(ctl, met, met->h2o, "H2O");
6651 read_met_ml2pl(ctl, met, met->o3, "O3");
6652 read_met_ml2pl(ctl, met, met->lwc, "LWC");
6653 read_met_ml2pl(ctl, met, met->rwc, "RWC");
6654 read_met_ml2pl(ctl, met, met->iwc, "IWC");
6655 read_met_ml2pl(ctl, met, met->swc, "SWC");
6656 read_met_ml2pl(ctl, met, met->cc, "CC");
6657
6658 /* Set new pressure levels... */
6659 met->np = ctl->met_np;
6660 for (int ip = 0; ip < met->np; ip++)
6661 met->p[ip] = ctl->met_p[ip];
6662 }
6663
6664 /* Check ordering of pressure levels... */
6665 for (int ip = 1; ip < met->np; ip++)
6666 if (met->p[ip - 1] < met->p[ip])
6667 ERRMSG("Pressure levels must be descending!");
6668}
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:6672
int read_met_nc_3d(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const ctl_t *ctl, const met_t *met, float dest[EX][EY][EP], const float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:7024
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:197
#define MO3
Molar mass of ozone [g/mol].
Definition: mptrac.h:202
int met_vert_coord
Vertical coordinate of input meteo data (0=pressure-level, 1=model-level).
Definition: mptrac.h:2170
Here is the call graph for this function:

◆ read_met_ml2pl()

void read_met_ml2pl ( const ctl_t ctl,
const met_t met,
float  var[EX][EY][EP],
const char *  varname 
)

Interpolates meteorological data to specified pressure levels.

This function interpolates meteorological data from model levels to pressure levels. The interpolation is performed in parallel over the spatial grid defined in the meteorological data structure.

Parameters
[in]ctlA pointer to a control structure containing the number of pressure levels (met_np) and the pressure levels themselves (met_p).
[in]metA pointer to a meteorological data structure containing the grid dimensions (nx, ny) and the pressure profile (pl).
[in,out]varA 3D array containing the meteorological variable to be interpolated. On output, this array will contain the interpolated values at the specified pressure levels.
[in]varnameA string representing the name of the meteorological variable being interpolated.

This function performs the following steps:

  • Sets a timer for the operation.
  • Logs the start of the interpolation process with the variable name.
  • Loops over the spatial columns (grid points).
  • For each column, copies the pressure profile.
  • Interpolates the meteorological variable to the specified pressure levels.
  • Copies the interpolated data back into the var array.
Note
The interpolation is performed in parallel using OpenMP.
Author
Lars Hoffmann

Definition at line 6672 of file mptrac.c.

6676 {
6677
6678 double aux[EP], p[EP];
6679
6680 /* Set timer... */
6681 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
6682 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
6683
6684 /* Loop over columns... */
6685#pragma omp parallel for default(shared) private(aux,p) collapse(2)
6686 for (int ix = 0; ix < met->nx; ix++)
6687 for (int iy = 0; iy < met->ny; iy++) {
6688
6689 /* Copy pressure profile... */
6690 for (int ip = 0; ip < met->np; ip++)
6691 p[ip] = met->pl[ix][iy][ip];
6692
6693 /* Interpolate... */
6694 for (int ip = 0; ip < ctl->met_np; ip++) {
6695 double pt = ctl->met_p[ip];
6696 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
6697 pt = p[0];
6698 else if ((pt > p[met->np - 1] && p[1] > p[0])
6699 || (pt < p[met->np - 1] && p[1] < p[0]))
6700 pt = p[met->np - 1];
6701 int ip2 = locate_irr(p, met->np, pt);
6702 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
6703 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
6704 }
6705
6706 /* Copy data... */
6707 for (int ip = 0; ip < ctl->met_np; ip++)
6708 var[ix][iy][ip] = (float) aux[ip];
6709 }
6710}
Here is the call graph for this function:

◆ read_met_monotonize()

void read_met_monotonize ( 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
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 6714 of file mptrac.c.

6715 {
6716
6717 /* Set timer... */
6718 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
6719 LOG(2, "Make zeta profiles monotone...");
6720
6721 /* Create monotone zeta profiles... */
6722#pragma omp parallel for default(shared) collapse(2)
6723 for (int i = 0; i < met->nx; i++)
6724 for (int j = 0; j < met->ny; j++) {
6725 int k = 1;
6726
6727 while (k < met->npl) { /* Check if there is an inversion at level k... */
6728 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
6729 /* Find the upper level k+l over the inversion... */
6730 int l = 0;
6731 do {
6732 l++;
6733 }
6734 while ((met->zetal[i][j][k - 1] >=
6735 met->zetal[i][j][k + l]) & (k + l < met->npl));
6736
6737 /* Interpolate linear between the top and bottom
6738 of the inversion... */
6739 float s =
6740 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
6741 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
6742
6743 for (int m = k; m < k + l; m++) {
6744 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
6745 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
6746 }
6747
6748 /* Search for more inversions above the last inversion ... */
6749 k = k + l;
6750 } else {
6751 k++;
6752 }
6753 }
6754 }
6755
6756 /* Create monotone pressure profiles... */
6757#pragma omp parallel for default(shared) collapse(2)
6758 for (int i = 0; i < met->nx; i++)
6759 for (int j = 0; j < met->ny; j++) {
6760 int k = 1;
6761
6762 while (k < met->npl) { /* Check if there is an inversion at level k... */
6763 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
6764
6765 /* Find the upper level k+l over the inversion... */
6766 int l = 0;
6767 do {
6768 l++;
6769 }
6770 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
6771 met->npl));
6772
6773 /* Interpolate linear between the top and bottom
6774 of the inversion... */
6775 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
6776 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
6777
6778 for (int m = k; m < k + l; m++) {
6779 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
6780 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
6781 }
6782
6783 /* Search for more inversions above the last inversion ... */
6784 k += l;
6785 } else {
6786 k++;
6787 }
6788 }
6789 }
6790}

◆ read_met_nc()

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

Reads meteorological data from a NetCDF file and processes it.

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

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

Definition at line 6794 of file mptrac.c.

6798 {
6799
6800 int ncid;
6801
6802 /* Open netCDF file... */
6803 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6804 WARN("Cannot open file!");
6805 return 0;
6806 }
6807
6808 /* Read coordinates of meteo data... */
6809 read_met_grid(filename, ncid, ctl, met);
6810
6811 /* Read meteo data on vertical levels... */
6812 read_met_levels(ncid, ctl, met);
6813
6814 /* Extrapolate data for lower boundary... */
6816
6817 /* Read surface data... */
6818 read_met_surface(ncid, ctl, met);
6819
6820 /* Fix polar winds... */
6822
6823 /* Create periodic boundary conditions... */
6824 read_met_periodic(met);
6825
6826 /* Downsampling... */
6827 read_met_sample(ctl, met);
6828
6829 /* Calculate geopotential heights... */
6830 read_met_geopot(ctl, met);
6831
6832 /* Calculate potential vorticity... */
6833 read_met_pv(met);
6834
6835 /* Calculate boundary layer data... */
6836 read_met_pbl(ctl, met);
6837
6838 /* Calculate tropopause data... */
6839 read_met_tropo(ctl, clim, met);
6840
6841 /* Calculate cloud properties... */
6842 read_met_cloud(met);
6843
6844 /* Calculate convective available potential energy... */
6845 read_met_cape(ctl, clim, met);
6846
6847 /* Calculate total column ozone... */
6848 read_met_ozone(met);
6849
6850 /* Detrending... */
6851 read_met_detrend(ctl, met);
6852
6853 /* Check meteo data and smooth zeta profiles ... */
6854 if (ctl->advect_vert_coord == 1)
6856
6857 /* Close file... */
6858 NC(nc_close(ncid));
6859
6860 /* Return success... */
6861 return 1;
6862}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:6290
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:6250
void read_met_levels(const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological variables at different vertical levels from a NetCDF file.
Definition: mptrac.c:6536
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:7565
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:6089
void read_met_pbl(const ctl_t *ctl, met_t *met)
Computes the planetary boundary layer (PBL) height based on meteorological data.
Definition: mptrac.c:7170
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:6146
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:7316
void read_met_grid(const char *filename, const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological grid information from a NetCDF file.
Definition: mptrac.c:6418
void read_met_monotonize(met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:6714
void read_met_surface(const int ncid, const ctl_t *ctl, met_t *met)
Reads surface meteorological data from a netCDF file and stores it in the meteorological data structu...
Definition: mptrac.c:7713
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:7536
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:7430
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:7371
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:5974
Here is the call graph for this function:

◆ read_met_nc_2d()

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

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

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

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

The function performs the following steps:

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

Definition at line 6866 of file mptrac.c.

6878 {
6879
6880 char varsel[LEN];
6881
6882 float offset, scalfac;
6883
6884 int varid;
6885
6886 /* Check if variable exists... */
6887 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
6888 sprintf(varsel, "%s", varname);
6889 else if (varname2 != NULL
6890 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
6891 sprintf(varsel, "%s", varname2);
6892 else if (varname3 != NULL
6893 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
6894 sprintf(varsel, "%s", varname3);
6895 else if (varname4 != NULL
6896 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
6897 sprintf(varsel, "%s", varname4);
6898 else if (varname5 != NULL
6899 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
6900 sprintf(varsel, "%s", varname5);
6901 else if (varname6 != NULL
6902 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
6903 sprintf(varsel, "%s", varname6);
6904 else
6905 return 0;
6906
6907 /* Read packed data... */
6908 if (ctl->met_nc_scale
6909 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
6910 && nc_get_att_float(ncid, varid, "scale_factor",
6911 &scalfac) == NC_NOERR) {
6912
6913 /* Allocate... */
6914 short *help;
6915 ALLOC(help, short,
6916 EX * EY * EP);
6917
6918 /* Read fill value and missing value... */
6919 short fillval, missval;
6920 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
6921 fillval = 0;
6922 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
6923 missval = 0;
6924
6925 /* Write info... */
6926 LOG(2, "Read 2-D variable: %s"
6927 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
6928 varsel, fillval, missval, scalfac, offset);
6929
6930 /* Read data... */
6931 NC(nc_get_var_short(ncid, varid, help));
6932
6933 /* Check meteo data layout... */
6934 if (ctl->met_convention != 0)
6935 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
6936
6937 /* Copy and check data... */
6938#pragma omp parallel for default(shared) num_threads(12)
6939 for (int ix = 0; ix < met->nx; ix++)
6940 for (int iy = 0; iy < met->ny; iy++) {
6941 if (init)
6942 dest[ix][iy] = 0;
6943 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
6944 if ((fillval == 0 || aux != fillval)
6945 && (missval == 0 || aux != missval)
6946 && fabsf(aux * scalfac + offset) < 1e14f)
6947 dest[ix][iy] += scl * (aux * scalfac + offset);
6948 else
6949 dest[ix][iy] = NAN;
6950 }
6951
6952 /* Free... */
6953 free(help);
6954 }
6955
6956 /* Unpacked data... */
6957 else {
6958
6959 /* Allocate... */
6960 float *help;
6961 ALLOC(help, float,
6962 EX * EY);
6963
6964 /* Read fill value and missing value... */
6965 float fillval, missval;
6966 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
6967 fillval = 0;
6968 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
6969 missval = 0;
6970
6971 /* Write info... */
6972 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
6973 varsel, fillval, missval);
6974
6975 /* Read data... */
6976 NC(nc_get_var_float(ncid, varid, help));
6977
6978 /* Check meteo data layout... */
6979 if (ctl->met_convention == 0) {
6980
6981 /* Copy and check data (ordering: lat, lon)... */
6982#pragma omp parallel for default(shared) num_threads(12)
6983 for (int ix = 0; ix < met->nx; ix++)
6984 for (int iy = 0; iy < met->ny; iy++) {
6985 if (init)
6986 dest[ix][iy] = 0;
6987 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
6988 if ((fillval == 0 || aux != fillval)
6989 && (missval == 0 || aux != missval)
6990 && fabsf(aux) < 1e14f)
6991 dest[ix][iy] += scl * aux;
6992 else
6993 dest[ix][iy] = NAN;
6994 }
6995
6996 } else {
6997
6998 /* Copy and check data (ordering: lon, lat)... */
6999#pragma omp parallel for default(shared) num_threads(12)
7000 for (int iy = 0; iy < met->ny; iy++)
7001 for (int ix = 0; ix < met->nx; ix++) {
7002 if (init)
7003 dest[ix][iy] = 0;
7004 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
7005 if ((fillval == 0 || aux != fillval)
7006 && (missval == 0 || aux != missval)
7007 && fabsf(aux) < 1e14f)
7008 dest[ix][iy] += scl * aux;
7009 else
7010 dest[ix][iy] = NAN;
7011 }
7012 }
7013
7014 /* Free... */
7015 free(help);
7016 }
7017
7018 /* Return... */
7019 return 1;
7020}
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2488
int met_convention
Meteo data layout (0=[lev, lat, lon], 1 = [lon, lat, lev]).
Definition: mptrac.h:2481

◆ read_met_nc_3d()

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

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

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

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

The function performs the following steps:

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

Definition at line 7024 of file mptrac.c.

7033 {
7034
7035 char varsel[LEN];
7036
7037 float offset, scalfac;
7038
7039 int varid;
7040
7041 /* Check if variable exists... */
7042 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7043 sprintf(varsel, "%s", varname);
7044 else if (varname2 != NULL
7045 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7046 sprintf(varsel, "%s", varname2);
7047 else if (varname3 != NULL
7048 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7049 sprintf(varsel, "%s", varname3);
7050 else if (varname4 != NULL
7051 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7052 sprintf(varsel, "%s", varname4);
7053 else
7054 return 0;
7055
7056 /* Read packed data... */
7057 if (ctl->met_nc_scale
7058 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7059 && nc_get_att_float(ncid, varid, "scale_factor",
7060 &scalfac) == NC_NOERR) {
7061
7062 /* Allocate... */
7063 short *help;
7064 ALLOC(help, short,
7065 EX * EY * EP);
7066
7067 /* Read fill value and missing value... */
7068 short fillval, missval;
7069 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7070 fillval = 0;
7071 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7072 missval = 0;
7073
7074 /* Write info... */
7075 LOG(2, "Read 3-D variable: %s "
7076 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7077 varsel, fillval, missval, scalfac, offset);
7078
7079 /* Read data... */
7080 NC(nc_get_var_short(ncid, varid, help));
7081
7082 /* Check meteo data layout... */
7083 if (ctl->met_convention != 0)
7084 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7085
7086 /* Copy and check data... */
7087#pragma omp parallel for default(shared) num_threads(12)
7088 for (int ix = 0; ix < met->nx; ix++)
7089 for (int iy = 0; iy < met->ny; iy++)
7090 for (int ip = 0; ip < met->np; ip++) {
7091 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7092 if ((fillval == 0 || aux != fillval)
7093 && (missval == 0 || aux != missval)
7094 && fabsf(aux * scalfac + offset) < 1e14f)
7095 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
7096 else
7097 dest[ix][iy][ip] = NAN;
7098 }
7099
7100 /* Free... */
7101 free(help);
7102 }
7103
7104 /* Unpacked data... */
7105 else {
7106
7107 /* Allocate... */
7108 float *help;
7109 ALLOC(help, float,
7110 EX * EY * EP);
7111
7112 /* Read fill value and missing value... */
7113 float fillval, missval;
7114 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7115 fillval = 0;
7116 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7117 missval = 0;
7118
7119 /* Write info... */
7120 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
7121 varsel, fillval, missval);
7122
7123 /* Read data... */
7124 NC(nc_get_var_float(ncid, varid, help));
7125
7126 /* Check meteo data layout... */
7127 if (ctl->met_convention == 0) {
7128
7129 /* Copy and check data (ordering: lev, lat, lon)... */
7130#pragma omp parallel for default(shared) num_threads(12)
7131 for (int ix = 0; ix < met->nx; ix++)
7132 for (int iy = 0; iy < met->ny; iy++)
7133 for (int ip = 0; ip < met->np; ip++) {
7134 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7135 if ((fillval == 0 || aux != fillval)
7136 && (missval == 0 || aux != missval)
7137 && fabsf(aux) < 1e14f)
7138 dest[ix][iy][ip] = scl * aux;
7139 else
7140 dest[ix][iy][ip] = NAN;
7141 }
7142
7143 } else {
7144
7145 /* Copy and check data (ordering: lon, lat, lev)... */
7146#pragma omp parallel for default(shared) num_threads(12)
7147 for (int ip = 0; ip < met->np; ip++)
7148 for (int iy = 0; iy < met->ny; iy++)
7149 for (int ix = 0; ix < met->nx; ix++) {
7150 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7151 if ((fillval == 0 || aux != fillval)
7152 && (missval == 0 || aux != missval)
7153 && fabsf(aux) < 1e14f)
7154 dest[ix][iy][ip] = scl * aux;
7155 else
7156 dest[ix][iy][ip] = NAN;
7157 }
7158 }
7159
7160 /* Free... */
7161 free(help);
7162 }
7163
7164 /* Return... */
7165 return 1;
7166}

◆ read_met_pbl()

void read_met_pbl ( const ctl_t ctl,
met_t met 
)

Computes the planetary boundary layer (PBL) height based on meteorological data.

This function calculates the PBL height for each grid point using one of three methods:

  1. From precomputed values in the meteorological data file.
  2. Based on the bulk Richardson number criterion.
  3. 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 heights.

Method 0 (Precomputed PBL height from file):

  • Interpolates the PBL height using the pressure at the top of the PBL and the meteorological vertical profile.

Method 1 (Richardson number criterion):

  • Implements a method based on the bulk Richardson number (critical value: 0.25).
  • Iteratively evaluates vertical levels, calculating wind shear, and thermal gradients, until the Richardson number exceeds the critical threshold.
  • Interpolates the PBL height at the critical Richardson number.

Method 2 (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 1 is a standard method for estimating PBL depths, but the current implementation seems to significantly underestimate PBL depths compared to ECMWF data or Method 2. Therefore, Method 2, is selected by default. If PBL data are available from the meteo data files, it is recommended to select Method 0.
Author
Lars Hoffmann

Definition at line 7170 of file mptrac.c.

7172 {
7173
7174 /* Set timer... */
7175 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
7176 LOG(2, "Calculate planetary boundary layer...");
7177
7178 /* Get PBL from meteo file... */
7179 if (ctl->met_pbl == 0) {
7180
7181 /* Loop over grid points... */
7182#pragma omp parallel for default(shared) collapse(2)
7183 for (int ix = 0; ix < met->nx; ix++)
7184 for (int iy = 0; iy < met->ny; iy++) {
7185
7186 /* Get pressure at top of PBL... */
7187 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
7188 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
7189 met->pbl[ix][iy] =
7190 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
7191 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
7192 }
7193 }
7194
7195 /* Determine PBL based on Richardson number... */
7196 else if (ctl->met_pbl == 1) {
7197
7198 /* Parameters used to estimate the height of the PBL
7199 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
7200 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
7201
7202 /* Loop over grid points... */
7203#pragma omp parallel for default(shared) collapse(2)
7204 for (int ix = 0; ix < met->nx; ix++)
7205 for (int iy = 0; iy < met->ny; iy++) {
7206
7207 /* Set bottom level of PBL... */
7208 const double pbl_bot = met->ps[ix][iy] + DZ2DP(dz, met->ps[ix][iy]);
7209
7210 /* Find lowest level near the bottom... */
7211 int ip;
7212 for (ip = 1; ip < met->np; ip++)
7213 if (met->p[ip] < pbl_bot)
7214 break;
7215
7216 /* Get near surface data... */
7217 const double zs = LIN(met->p[ip - 1], met->z[ix][iy][ip - 1],
7218 met->p[ip], met->z[ix][iy][ip], pbl_bot);
7219 const double ts = LIN(met->p[ip - 1], met->t[ix][iy][ip - 1],
7220 met->p[ip], met->t[ix][iy][ip], pbl_bot);
7221 const double us = LIN(met->p[ip - 1], met->u[ix][iy][ip - 1],
7222 met->p[ip], met->u[ix][iy][ip], pbl_bot);
7223 const double vs = LIN(met->p[ip - 1], met->v[ix][iy][ip - 1],
7224 met->p[ip], met->v[ix][iy][ip], pbl_bot);
7225 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
7226 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
7227 const double tvs = THETAVIRT(pbl_bot, ts, h2os);
7228
7229 /* Init... */
7230 double rib_old = 0;
7231
7232 /* Loop over levels... */
7233 for (; ip < met->np; ip++) {
7234
7235 /* Get squared horizontal wind speed... */
7236 double vh2
7237 = SQR(met->u[ix][iy][ip] - us) + SQR(met->v[ix][iy][ip] - vs);
7238 vh2 = MAX(vh2, SQR(umin));
7239
7240 /* Calculate bulk Richardson number... */
7241 const double rib = G0 * 1e3 * (met->z[ix][iy][ip] - zs) / tvs
7242 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
7243 met->h2o[ix][iy][ip]) - tvs) / vh2;
7244
7245 /* Check for critical value... */
7246 if (rib >= rib_crit) {
7247 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
7248 rib, met->p[ip], rib_crit));
7249 if (met->pbl[ix][iy] > pbl_bot)
7250 met->pbl[ix][iy] = (float) pbl_bot;
7251 break;
7252 }
7253
7254 /* Save Richardson number... */
7255 rib_old = rib;
7256 }
7257 }
7258 }
7259
7260 /* Determine PBL based on potential temperature... */
7261 if (ctl->met_pbl == 2) {
7262
7263 /* Parameters used to estimate the height of the PBL
7264 (following HYSPLIT model)... */
7265 const double dtheta = 2.0, zmin = 0.1;
7266
7267 /* Loop over grid points... */
7268#pragma omp parallel for default(shared) collapse(2)
7269 for (int ix = 0; ix < met->nx; ix++)
7270 for (int iy = 0; iy < met->ny; iy++) {
7271
7272 /* Potential temperature at the surface... */
7273 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
7274
7275 /* Find topmost level where theta exceeds surface value by 2 K... */
7276 int ip;
7277 for (ip = met->np - 2; ip > 0; ip--)
7278 if (met->p[ip] >= 300.)
7279 if (met->p[ip] > met->ps[ix][iy]
7280 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
7281 break;
7282
7283 /* Interpolate... */
7284 met->pbl[ix][iy]
7285 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
7286 met->p[ip + 1],
7287 THETA(met->p[ip], met->t[ix][iy][ip]),
7288 met->p[ip], theta0 + dtheta));
7289
7290 /* Check minimum value... */
7291 double pbl_min = met->ps[ix][iy] + DZ2DP(zmin, met->ps[ix][iy]);
7292 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
7293 met->pbl[ix][iy] = (float) pbl_min;
7294 }
7295 }
7296
7297 /* Loop over grid points... */
7298#pragma omp parallel for default(shared) collapse(2)
7299 for (int ix = 0; ix < met->nx; ix++)
7300 for (int iy = 0; iy < met->ny; iy++) {
7301
7302 /* Check minimum value... */
7303 double pbl_min =
7304 met->ps[ix][iy] + DZ2DP(ctl->met_pbl_min, met->ps[ix][iy]);
7305 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
7306
7307 /* Check maximum value... */
7308 double pbl_max =
7309 met->ps[ix][iy] + DZ2DP(ctl->met_pbl_max, met->ps[ix][iy]);
7310 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
7311 }
7312}
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1658
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 7316 of file mptrac.c.

7317 {
7318
7319 /* Set timer... */
7320 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
7321 LOG(2, "Apply periodic boundary conditions...");
7322
7323 /* Check longitudes... */
7324 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
7325 + met->lon[1] - met->lon[0] - 360) < 0.01))
7326 return;
7327
7328 /* Increase longitude counter... */
7329 if ((++met->nx) >= EX)
7330 ERRMSG("Cannot create periodic boundary conditions!");
7331
7332 /* Set longitude... */
7333 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
7334
7335 /* Loop over latitudes and pressure levels... */
7336#pragma omp parallel for default(shared)
7337 for (int iy = 0; iy < met->ny; iy++) {
7338 met->ps[met->nx - 1][iy] = met->ps[0][iy];
7339 met->zs[met->nx - 1][iy] = met->zs[0][iy];
7340 met->ts[met->nx - 1][iy] = met->ts[0][iy];
7341 met->us[met->nx - 1][iy] = met->us[0][iy];
7342 met->vs[met->nx - 1][iy] = met->vs[0][iy];
7343 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
7344 met->sst[met->nx - 1][iy] = met->sst[0][iy];
7345 for (int ip = 0; ip < met->np; ip++) {
7346 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
7347 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
7348 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
7349 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
7350 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
7351 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
7352 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
7353 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
7354 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
7355 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
7356 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
7357 }
7358 for (int ip = 0; ip < met->npl; ip++) {
7359 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
7360 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
7361 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
7362 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
7363 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
7364 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
7365 }
7366 }
7367}

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

7372 {
7373
7374 /* Set timer... */
7375 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
7376 LOG(2, "Apply fix for polar winds...");
7377
7378 /* Check latitudes... */
7379 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
7380 return;
7381
7382 /* Loop over hemispheres... */
7383 for (int ihem = 0; ihem < 2; ihem++) {
7384
7385 /* Set latitude indices... */
7386 int i89 = 1, i90 = 0, sign = 1;
7387 if (ihem == 1) {
7388 i89 = met->ny - 2;
7389 i90 = met->ny - 1;
7390 }
7391 if (met->lat[i90] < 0)
7392 sign = -1;
7393
7394 /* Look-up table of cosinus and sinus... */
7395 double clon[EX], slon[EX];
7396#pragma omp parallel for default(shared)
7397 for (int ix = 0; ix < met->nx; ix++) {
7398 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
7399 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
7400 }
7401
7402 /* Loop over levels... */
7403#pragma omp parallel for default(shared)
7404 for (int ip = 0; ip < met->np; ip++) {
7405
7406 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
7407 double vel89x = 0, vel89y = 0;
7408 for (int ix = 0; ix < met->nx; ix++) {
7409 vel89x +=
7410 (met->u[ix][i89][ip] * clon[ix] -
7411 met->v[ix][i89][ip] * slon[ix]) / met->nx;
7412 vel89y +=
7413 (met->u[ix][i89][ip] * slon[ix] +
7414 met->v[ix][i89][ip] * clon[ix]) / met->nx;
7415 }
7416
7417 /* Replace 90 degree winds by 89 degree mean... */
7418 for (int ix = 0; ix < met->nx; ix++) {
7419 met->u[ix][i90][ip]
7420 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
7421 met->v[ix][i90][ip]
7422 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
7423 }
7424 }
7425 }
7426}

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

7431 {
7432
7433 double pows[EP];
7434
7435 /* Set timer... */
7436 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
7437 LOG(2, "Calculate potential vorticity...");
7438
7439 /* Set powers... */
7440#pragma omp parallel for default(shared)
7441 for (int ip = 0; ip < met->np; ip++)
7442 pows[ip] = pow(1000. / met->p[ip], 0.286);
7443
7444 /* Loop over grid points... */
7445#pragma omp parallel for default(shared)
7446 for (int ix = 0; ix < met->nx; ix++) {
7447
7448 /* Set indices... */
7449 const int ix0 = MAX(ix - 1, 0);
7450 const int ix1 = MIN(ix + 1, met->nx - 1);
7451
7452 /* Loop over grid points... */
7453 for (int iy = 0; iy < met->ny; iy++) {
7454
7455 /* Set indices... */
7456 const int iy0 = MAX(iy - 1, 0);
7457 const int iy1 = MIN(iy + 1, met->ny - 1);
7458
7459 /* Set auxiliary variables... */
7460 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
7461 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
7462 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
7463 const double c0 = cos(DEG2RAD(met->lat[iy0]));
7464 const double c1 = cos(DEG2RAD(met->lat[iy1]));
7465 const double cr = cos(DEG2RAD(latr));
7466 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
7467
7468 /* Loop over grid points... */
7469 for (int ip = 0; ip < met->np; ip++) {
7470
7471 /* Get gradients in longitude... */
7472 const double dtdx
7473 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
7474 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
7475
7476 /* Get gradients in latitude... */
7477 const double dtdy
7478 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
7479 const double dudy
7480 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
7481
7482 /* Set indices... */
7483 const int ip0 = MAX(ip - 1, 0);
7484 const int ip1 = MIN(ip + 1, met->np - 1);
7485
7486 /* Get gradients in pressure... */
7487 double dtdp, dudp, dvdp;
7488 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
7489 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
7490 if (ip != ip0 && ip != ip1) {
7491 double denom = dp0 * dp1 * (dp0 + dp1);
7492 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
7493 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
7494 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
7495 / denom;
7496 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
7497 - dp1 * dp1 * met->u[ix][iy][ip0]
7498 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
7499 / denom;
7500 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
7501 - dp1 * dp1 * met->v[ix][iy][ip0]
7502 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
7503 / denom;
7504 } else {
7505 const double denom = dp0 + dp1;
7506 dtdp =
7507 (met->t[ix][iy][ip1] * pows[ip1] -
7508 met->t[ix][iy][ip0] * pows[ip0]) / denom;
7509 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
7510 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
7511 }
7512
7513 /* Calculate PV... */
7514 met->pv[ix][iy][ip] = (float)
7515 (1e6 * G0 *
7516 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
7517 }
7518 }
7519 }
7520
7521 /* Fix for polar regions... */
7522#pragma omp parallel for default(shared)
7523 for (int ix = 0; ix < met->nx; ix++)
7524 for (int ip = 0; ip < met->np; ip++) {
7525 met->pv[ix][0][ip]
7526 = met->pv[ix][1][ip]
7527 = met->pv[ix][2][ip];
7528 met->pv[ix][met->ny - 1][ip]
7529 = met->pv[ix][met->ny - 2][ip]
7530 = met->pv[ix][met->ny - 3][ip];
7531 }
7532}
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:459
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:438

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

7537 {
7538
7539 /* Set timer... */
7540 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
7541 LOG(2, "Calculate total column ozone...");
7542
7543 /* Loop over columns... */
7544#pragma omp parallel for default(shared) collapse(2)
7545 for (int ix = 0; ix < met->nx; ix++)
7546 for (int iy = 0; iy < met->ny; iy++) {
7547
7548 /* Integrate... */
7549 double cd = 0;
7550 for (int ip = 1; ip < met->np; ip++)
7551 if (met->p[ip - 1] <= met->ps[ix][iy]) {
7552 const double vmr =
7553 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
7554 const double dp = met->p[ip - 1] - met->p[ip];
7555 cd += vmr * MO3 / MA * dp * 1e2 / G0;
7556 }
7557
7558 /* Convert to Dobson units... */
7559 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
7560 }
7561}
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3431

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

7567 {
7568
7569 met_t *help;
7570
7571 /* Check parameters... */
7572 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
7573 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
7574 return;
7575
7576 /* Set timer... */
7577 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
7578 LOG(2, "Downsampling of meteo data...");
7579
7580 /* Allocate... */
7581 ALLOC(help, met_t, 1);
7582
7583 /* Copy data... */
7584 help->nx = met->nx;
7585 help->ny = met->ny;
7586 help->np = met->np;
7587 memcpy(help->lon, met->lon, sizeof(met->lon));
7588 memcpy(help->lat, met->lat, sizeof(met->lat));
7589 memcpy(help->p, met->p, sizeof(met->p));
7590
7591 /* Smoothing... */
7592 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
7593 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
7594 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
7595 help->ps[ix][iy] = 0;
7596 help->zs[ix][iy] = 0;
7597 help->ts[ix][iy] = 0;
7598 help->us[ix][iy] = 0;
7599 help->vs[ix][iy] = 0;
7600 help->lsm[ix][iy] = 0;
7601 help->sst[ix][iy] = 0;
7602 help->t[ix][iy][ip] = 0;
7603 help->u[ix][iy][ip] = 0;
7604 help->v[ix][iy][ip] = 0;
7605 help->w[ix][iy][ip] = 0;
7606 help->h2o[ix][iy][ip] = 0;
7607 help->o3[ix][iy][ip] = 0;
7608 help->lwc[ix][iy][ip] = 0;
7609 help->rwc[ix][iy][ip] = 0;
7610 help->iwc[ix][iy][ip] = 0;
7611 help->swc[ix][iy][ip] = 0;
7612 help->cc[ix][iy][ip] = 0;
7613 float wsum = 0;
7614 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
7615 ix2++) {
7616 int ix3 = ix2;
7617 if (ix3 < 0)
7618 ix3 += met->nx;
7619 else if (ix3 >= met->nx)
7620 ix3 -= met->nx;
7621
7622 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
7623 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
7624 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
7625 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
7626 float w = (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
7627 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
7628 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
7629 help->ps[ix][iy] += w * met->ps[ix3][iy2];
7630 help->zs[ix][iy] += w * met->zs[ix3][iy2];
7631 help->ts[ix][iy] += w * met->ts[ix3][iy2];
7632 help->us[ix][iy] += w * met->us[ix3][iy2];
7633 help->vs[ix][iy] += w * met->vs[ix3][iy2];
7634 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
7635 help->sst[ix][iy] += w * met->sst[ix3][iy2];
7636 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
7637 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
7638 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
7639 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
7640 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
7641 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
7642 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
7643 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
7644 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
7645 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
7646 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
7647 wsum += w;
7648 }
7649 }
7650 help->ps[ix][iy] /= wsum;
7651 help->zs[ix][iy] /= wsum;
7652 help->ts[ix][iy] /= wsum;
7653 help->us[ix][iy] /= wsum;
7654 help->vs[ix][iy] /= wsum;
7655 help->lsm[ix][iy] /= wsum;
7656 help->sst[ix][iy] /= wsum;
7657 help->t[ix][iy][ip] /= wsum;
7658 help->u[ix][iy][ip] /= wsum;
7659 help->v[ix][iy][ip] /= wsum;
7660 help->w[ix][iy][ip] /= wsum;
7661 help->h2o[ix][iy][ip] /= wsum;
7662 help->o3[ix][iy][ip] /= wsum;
7663 help->lwc[ix][iy][ip] /= wsum;
7664 help->rwc[ix][iy][ip] /= wsum;
7665 help->iwc[ix][iy][ip] /= wsum;
7666 help->swc[ix][iy][ip] /= wsum;
7667 help->cc[ix][iy][ip] /= wsum;
7668 }
7669 }
7670 }
7671
7672 /* Downsampling... */
7673 met->nx = 0;
7674 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
7675 met->lon[met->nx] = help->lon[ix];
7676 met->ny = 0;
7677 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
7678 met->lat[met->ny] = help->lat[iy];
7679 met->ps[met->nx][met->ny] = help->ps[ix][iy];
7680 met->zs[met->nx][met->ny] = help->zs[ix][iy];
7681 met->ts[met->nx][met->ny] = help->ts[ix][iy];
7682 met->us[met->nx][met->ny] = help->us[ix][iy];
7683 met->vs[met->nx][met->ny] = help->vs[ix][iy];
7684 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
7685 met->sst[met->nx][met->ny] = help->sst[ix][iy];
7686 met->np = 0;
7687 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
7688 met->p[met->np] = help->p[ip];
7689 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
7690 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
7691 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
7692 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
7693 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
7694 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
7695 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
7696 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
7697 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
7698 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
7699 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
7700 met->np++;
7701 }
7702 met->ny++;
7703 }
7704 met->nx++;
7705 }
7706
7707 /* Free... */
7708 free(help);
7709}
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2558
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2564
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2561
int met_dx
Stride for longitudes.
Definition: mptrac.h:2552
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2567
int met_dy
Stride for latitudes.
Definition: mptrac.h:2555

◆ read_met_surface()

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

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

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

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

The function performs the following steps:

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

Definition at line 7713 of file mptrac.c.

7716 {
7717
7718 /* Set timer... */
7719 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
7720 LOG(2, "Read surface data...");
7721
7722 /* Read surface pressure... */
7723 if (read_met_nc_2d
7724 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, met->ps, 1.0f,
7725 1)) {
7726 for (int ix = 0; ix < met->nx; ix++)
7727 for (int iy = 0; iy < met->ny; iy++)
7728 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
7729 } else
7730 if (!read_met_nc_2d
7731 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, met->ps, 0.01f,
7732 1)) {
7733 WARN("Cannot not read surface pressure data (use lowest level)!");
7734 for (int ix = 0; ix < met->nx; ix++)
7735 for (int iy = 0; iy < met->ny; iy++)
7736 met->ps[ix][iy] = (float) met->p[0];
7737 }
7738
7739 /* MPTRAC meteo data... */
7740 if (ctl->met_clams == 0) {
7741
7742 /* Read geopotential height at the surface... */
7743 if (!read_met_nc_2d
7744 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, met->zs,
7745 (float) (1. / (1000. * G0)), 1))
7746 if (!read_met_nc_2d
7747 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, met->zs,
7748 (float) (1. / 1000.), 1))
7749 WARN("Cannot read surface geopotential height!");
7750 }
7751
7752 /* CLaMS meteo data... */
7753 else {
7754
7755 /* Read geopotential height at the surface
7756 (use lowermost level of 3-D data field)... */
7757 float *help;
7758 ALLOC(help, float,
7759 EX * EY * EP);
7760 memcpy(help, met->pl, sizeof(met->pl));
7761 if (!read_met_nc_3d
7762 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
7763 (float) (1e-3 / G0)))
7764 ERRMSG("Cannot read geopotential height!");
7765 for (int ix = 0; ix < met->nx; ix++)
7766 for (int iy = 0; iy < met->ny; iy++)
7767 met->zs[ix][iy] = met->pl[ix][iy][0];
7768 memcpy(met->pl, help, sizeof(met->pl));
7769 free(help);
7770 }
7771
7772 /* Read temperature at the surface... */
7773 if (!read_met_nc_2d
7774 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, met->ts, 1.0, 1))
7775 WARN("Cannot read surface temperature!");
7776
7777 /* Read zonal wind at the surface... */
7778 if (!read_met_nc_2d
7779 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, met->us,
7780 1.0, 1))
7781 WARN("Cannot read surface zonal wind!");
7782
7783 /* Read meridional wind at the surface... */
7784 if (!read_met_nc_2d
7785 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, met->vs,
7786 1.0, 1))
7787 WARN("Cannot read surface meridional wind!");
7788
7789 /* Read land-sea mask... */
7790 if (!read_met_nc_2d
7791 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, met->lsm, 1.0,
7792 1))
7793 WARN("Cannot read land-sea mask!");
7794
7795 /* Read sea surface temperature... */
7796 if (!read_met_nc_2d
7797 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, met->sst,
7798 1.0, 1))
7799 WARN("Cannot read sea surface temperature!");
7800
7801 /* Read CAPE... */
7802 if (ctl->met_cape == 0)
7803 if (!read_met_nc_2d
7804 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, met->cape,
7805 1.0, 1))
7806 WARN("Cannot read CAPE!");
7807
7808 /* Read CIN... */
7809 if (ctl->met_cape == 0)
7810 if (!read_met_nc_2d
7811 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, met->cin,
7812 1.0, 1))
7813 WARN("Cannot read convective inhibition!");
7814
7815 /* Read PBL... */
7816 if (ctl->met_pbl == 0)
7817 if (!read_met_nc_2d
7818 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
7819 0.001f, 1))
7820 ERRMSG("Cannot read planetary boundary layer!");
7821}
int read_met_nc_2d(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const char *varname5, const char *varname6, const ctl_t *ctl, const met_t *met, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:6866
Here is the call graph for this function:

◆ read_met_tropo()

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

Calculates the tropopause and related meteorological variables based on various methods and stores the results in the meteorological data structure.

This function calculates the tropopause and related meteorological variables using different methods specified by the control parameters. The calculated tropopause pressure is stored in the provided meteorological data structure.

Parameters
ctlA pointer to a structure containing control parameters.
climA pointer to the climatological data structure.
metA pointer to the meteorological data structure to store the calculated tropopause pressure and related variables.

The function performs the following steps:

  • Sets a timer for performance monitoring.
  • Retrieves altitude and pressure profiles from the meteorological data structure.
  • Depending on the control parameters (ctl->met_tropo), it calculates the tropopause using one of the following methods:
    • If ctl->met_tropo == 0, it does not calculate the tropopause and assigns NaN values to the tropopause pressure.
    • If ctl->met_tropo == 1, it uses tropopause climatology to estimate the tropopause pressure based on latitude and time.
    • If ctl->met_tropo == 2, it calculates the tropopause based on the cold point method, finding the altitude where the temperature is at a minimum.
    • If ctl->met_tropo == 3 or ctl->met_tropo == 4, it calculates the tropopause using the WMO definition, which involves identifying a sharp temperature lapse rate between two pressure levels.
    • If ctl->met_tropo == 5, it calculates the dynamical tropopause based on potential vorticity and potential temperature profiles.
  • Interpolates temperature, geopotential height, and water vapor content to the tropopause pressure level using spatial interpolation.
  • Stores the interpolated values in the meteorological data structure.
Note
The function supports parallelization using OpenMP directives to improve performance.
Author
Lars Hoffmann

Definition at line 7825 of file mptrac.c.

7828 {
7829
7830 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
7831 th2[200], z[EP], z2[200];
7832
7833 /* Set timer... */
7834 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
7835 LOG(2, "Calculate tropopause...");
7836
7837 /* Get altitude and pressure profiles... */
7838#pragma omp parallel for default(shared)
7839 for (int iz = 0; iz < met->np; iz++)
7840 z[iz] = Z(met->p[iz]);
7841#pragma omp parallel for default(shared)
7842 for (int iz = 0; iz <= 190; iz++) {
7843 z2[iz] = 4.5 + 0.1 * iz;
7844 p2[iz] = P(z2[iz]);
7845 }
7846
7847 /* Do not calculate tropopause... */
7848 if (ctl->met_tropo == 0)
7849#pragma omp parallel for default(shared) collapse(2)
7850 for (int ix = 0; ix < met->nx; ix++)
7851 for (int iy = 0; iy < met->ny; iy++)
7852 met->pt[ix][iy] = NAN;
7853
7854 /* Use tropopause climatology... */
7855 else if (ctl->met_tropo == 1) {
7856#pragma omp parallel for default(shared) collapse(2)
7857 for (int ix = 0; ix < met->nx; ix++)
7858 for (int iy = 0; iy < met->ny; iy++)
7859 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
7860 }
7861
7862 /* Use cold point... */
7863 else if (ctl->met_tropo == 2) {
7864
7865 /* Loop over grid points... */
7866#pragma omp parallel for default(shared) private(t,t2) collapse(2)
7867 for (int ix = 0; ix < met->nx; ix++)
7868 for (int iy = 0; iy < met->ny; iy++) {
7869
7870 /* Interpolate temperature profile... */
7871 for (int iz = 0; iz < met->np; iz++)
7872 t[iz] = met->t[ix][iy][iz];
7873 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
7874
7875 /* Find minimum... */
7876 int iz = (int) gsl_stats_min_index(t2, 1, 171);
7877 if (iz > 0 && iz < 170)
7878 met->pt[ix][iy] = (float) p2[iz];
7879 else
7880 met->pt[ix][iy] = NAN;
7881 }
7882 }
7883
7884 /* Use WMO definition... */
7885 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
7886
7887 /* Loop over grid points... */
7888#pragma omp parallel for default(shared) private(t,t2) collapse(2)
7889 for (int ix = 0; ix < met->nx; ix++)
7890 for (int iy = 0; iy < met->ny; iy++) {
7891
7892 /* Interpolate temperature profile... */
7893 int iz;
7894 for (iz = 0; iz < met->np; iz++)
7895 t[iz] = met->t[ix][iy][iz];
7896 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
7897
7898 /* Find 1st tropopause... */
7899 met->pt[ix][iy] = NAN;
7900 for (iz = 0; iz <= 170; iz++) {
7901 int found = 1;
7902 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
7903 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
7904 found = 0;
7905 break;
7906 }
7907 if (found) {
7908 if (iz > 0 && iz < 170)
7909 met->pt[ix][iy] = (float) p2[iz];
7910 break;
7911 }
7912 }
7913
7914 /* Find 2nd tropopause... */
7915 if (ctl->met_tropo == 4) {
7916 met->pt[ix][iy] = NAN;
7917 for (; iz <= 170; iz++) {
7918 int found = 1;
7919 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
7920 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
7921 found = 0;
7922 break;
7923 }
7924 if (found)
7925 break;
7926 }
7927 for (; iz <= 170; iz++) {
7928 int found = 1;
7929 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
7930 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
7931 found = 0;
7932 break;
7933 }
7934 if (found) {
7935 if (iz > 0 && iz < 170)
7936 met->pt[ix][iy] = (float) p2[iz];
7937 break;
7938 }
7939 }
7940 }
7941 }
7942 }
7943
7944 /* Use dynamical tropopause... */
7945 else if (ctl->met_tropo == 5) {
7946
7947 /* Loop over grid points... */
7948#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
7949 for (int ix = 0; ix < met->nx; ix++)
7950 for (int iy = 0; iy < met->ny; iy++) {
7951
7952 /* Interpolate potential vorticity profile... */
7953 for (int iz = 0; iz < met->np; iz++)
7954 pv[iz] = met->pv[ix][iy][iz];
7955 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
7956
7957 /* Interpolate potential temperature profile... */
7958 for (int iz = 0; iz < met->np; iz++)
7959 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
7960 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
7961
7962 /* Find dynamical tropopause... */
7963 met->pt[ix][iy] = NAN;
7964 for (int iz = 0; iz <= 170; iz++)
7965 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
7966 || th2[iz] >= ctl->met_tropo_theta) {
7967 if (iz > 0 && iz < 170)
7968 met->pt[ix][iy] = (float) p2[iz];
7969 break;
7970 }
7971 }
7972 }
7973
7974 else
7975 ERRMSG("Cannot calculate tropopause!");
7976
7977 /* Interpolate temperature, geopotential height, and water vapor... */
7978#pragma omp parallel for default(shared) collapse(2)
7979 for (int ix = 0; ix < met->nx; ix++)
7980 for (int iy = 0; iy < met->ny; iy++) {
7981 double h2ot, tt, zt;
7983 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
7984 met->lat[iy], &tt, ci, cw, 1);
7985 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
7986 met->lat[iy], &zt, ci, cw, 0);
7987 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
7988 met->lat[iy], &h2ot, ci, cw, 0);
7989 met->tt[ix][iy] = (float) tt;
7990 met->zt[ix][iy] = (float) zt;
7991 met->h2ot[ix][iy] = (float) h2ot;
7992 }
7993}
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:8203
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:828
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 7997 of file mptrac.c.

8005 {
8006
8007 /* Write info... */
8008 LOG(1, "Read observation data: %s", filename);
8009
8010 /* Read data... */
8011 if (ctl->obs_type == 0)
8012 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
8013 else if (ctl->obs_type == 1)
8014 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
8015 else
8016 ERRMSG("Set OBS_TYPE to 0 or 1!");
8017
8018 /* Check time... */
8019 for (int i = 1; i < *nobs; i++)
8020 if (rt[i] < rt[i - 1])
8021 ERRMSG("Time must be ascending!");
8022
8023 /* Write info... */
8024 int n = *nobs;
8025 double mini, maxi;
8026 LOG(2, "Number of observations: %d", *nobs);
8027 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
8028 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8029 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
8030 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
8031 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
8032 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
8033 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
8034 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
8035 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
8036 LOG(2, "Observation range: %g ... %g", mini, maxi);
8037}
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:8041
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:8069
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 8041 of file mptrac.c.

8048 {
8049
8050 /* Open observation data file... */
8051 FILE *in;
8052 if (!(in = fopen(filename, "r")))
8053 ERRMSG("Cannot open file!");
8054
8055 /* Read observations... */
8056 char line[LEN];
8057 while (fgets(line, LEN, in))
8058 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
8059 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
8060 if ((++(*nobs)) >= NOBS)
8061 ERRMSG("Too many observations!");
8062
8063 /* Close observation data file... */
8064 fclose(in);
8065}
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:279

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

8076 {
8077
8078 int ncid, varid;
8079
8080 /* Open netCDF file... */
8081 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8082 ERRMSG("Cannot open file!");
8083
8084 /* Read the observations from the NetCDF file... */
8085 NC_INQ_DIM("nobs", nobs, 1, NOBS);
8086 NC_GET_DOUBLE("time", rt, 1);
8087 NC_GET_DOUBLE("alt", rz, 1);
8088 NC_GET_DOUBLE("lon", rlon, 1);
8089 NC_GET_DOUBLE("lat", rlat, 1);
8090 NC_GET_DOUBLE("obs", robs, 1);
8091
8092 /* Close file... */
8093 NC(nc_close(ncid));
8094}

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

8105 {
8106
8107 FILE *in = NULL;
8108
8109 char fullname1[LEN], fullname2[LEN], rval[LEN];
8110
8111 int contain = 0, i;
8112
8113 /* Open file... */
8114 if (filename[strlen(filename) - 1] != '-')
8115 if (!(in = fopen(filename, "r")))
8116 ERRMSG("Cannot open file!");
8117
8118 /* Set full variable name... */
8119 if (arridx >= 0) {
8120 sprintf(fullname1, "%s[%d]", varname, arridx);
8121 sprintf(fullname2, "%s[*]", varname);
8122 } else {
8123 sprintf(fullname1, "%s", varname);
8124 sprintf(fullname2, "%s", varname);
8125 }
8126
8127 /* Read data... */
8128 if (in != NULL) {
8129 char dummy[LEN], line[LEN], rvarname[LEN];
8130 while (fgets(line, LEN, in)) {
8131 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
8132 if (strcasecmp(rvarname, fullname1) == 0 ||
8133 strcasecmp(rvarname, fullname2) == 0) {
8134 contain = 1;
8135 break;
8136 }
8137 }
8138 }
8139 for (i = 1; i < argc - 1; i++)
8140 if (strcasecmp(argv[i], fullname1) == 0 ||
8141 strcasecmp(argv[i], fullname2) == 0) {
8142 sprintf(rval, "%s", argv[i + 1]);
8143 contain = 1;
8144 break;
8145 }
8146
8147 /* Close file... */
8148 if (in != NULL)
8149 fclose(in);
8150
8151 /* Check for missing variables... */
8152 if (!contain) {
8153 if (strlen(defvalue) > 0)
8154 sprintf(rval, "%s", defvalue);
8155 else
8156 ERRMSG("Missing variable %s!\n", fullname1);
8157 }
8158
8159 /* Write info... */
8160 LOG(1, "%s = %s", fullname1, rval);
8161
8162 /* Return values... */
8163 if (value != NULL)
8164 sprintf(value, "%s", rval);
8165 return atof(rval);
8166}

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

8174 {
8175
8176 /* Convert particle radius from microns to m... */
8177 const double rp_help = rp * 1e-6;
8178
8179 /* Density of dry air [kg / m^3]... */
8180 const double rho = RHO(p, T);
8181
8182 /* Dynamic viscosity of air [kg / (m s)]... */
8183 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
8184
8185 /* Thermal velocity of an air molecule [m / s]... */
8186 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
8187
8188 /* Mean free path of an air molecule [m]... */
8189 const double lambda = 2. * eta / (rho * v);
8190
8191 /* Knudsen number for air (dimensionless)... */
8192 const double K = lambda / rp_help;
8193
8194 /* Cunningham slip-flow correction (dimensionless)... */
8195 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
8196
8197 /* Sedimentation velocity [m / s]... */
8198 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
8199}
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:187

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

8210 {
8211
8212 /* Cubic spline interpolation... */
8213 if (method == 1) {
8214
8215 /* Allocate... */
8216 gsl_interp_accel *acc;
8217 gsl_spline *s;
8218 acc = gsl_interp_accel_alloc();
8219 s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
8220
8221 /* Interpolate profile... */
8222 gsl_spline_init(s, x, y, (size_t) n);
8223 for (int i = 0; i < n2; i++)
8224 if (x2[i] <= x[0])
8225 y2[i] = y[0];
8226 else if (x2[i] >= x[n - 1])
8227 y2[i] = y[n - 1];
8228 else
8229 y2[i] = gsl_spline_eval(s, x2[i], acc);
8230
8231 /* Free... */
8232 gsl_spline_free(s);
8233 gsl_interp_accel_free(acc);
8234 }
8235
8236 /* Linear interpolation... */
8237 else {
8238 for (int i = 0; i < n2; i++)
8239 if (x2[i] <= x[0])
8240 y2[i] = y[0];
8241 else if (x2[i] >= x[n - 1])
8242 y2[i] = y[n - 1];
8243 else {
8244 int idx = locate_irr(x, n, x2[i]);
8245 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
8246 }
8247 }
8248}
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 8252 of file mptrac.c.

8254 {
8255
8256 if (n <= 0)
8257 return 0;
8258
8259 float mean = 0, var = 0;
8260
8261 for (int i = 0; i < n; ++i) {
8262 mean += data[i];
8263 var += SQR(data[i]);
8264 }
8265
8266 var = var / (float) n - SQR(mean / (float) n);
8267
8268 return (var > 0 ? sqrtf(var) : 0);
8269}

◆ sza_calc()

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

Calculates the solar zenith angle.

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

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

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

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

Definition at line 8273 of file mptrac.c.

8276 {
8277
8278 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
8279 const double D = sec / 86400 - 0.5;
8280
8281 /* Geocentric apparent ecliptic longitude [rad]... */
8282 const double g = DEG2RAD(357.529 + 0.98560028 * D);
8283 const double q = 280.459 + 0.98564736 * D;
8284 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
8285
8286 /* Mean obliquity of the ecliptic [rad]... */
8287 const double e = DEG2RAD(23.439 - 0.00000036 * D);
8288
8289 /* Declination [rad]... */
8290 const double sindec = sin(e) * sin(L);
8291
8292 /* Right ascension [rad]... */
8293 const double ra = atan2(cos(e) * sin(L), cos(L));
8294
8295 /* Greenwich Mean Sidereal Time [h]... */
8296 const double GMST = 18.697374558 + 24.06570982441908 * D;
8297
8298 /* Local Sidereal Time [h]... */
8299 const double LST = GMST + lon / 15;
8300
8301 /* Hour angle [rad]... */
8302 const double h = LST / 12 * M_PI - ra;
8303
8304 /* Convert latitude... */
8305 const double lat_help = DEG2RAD(lat);
8306
8307 /* Return solar zenith angle [rad]... */
8308 return acos(sin(lat_help) * sindec +
8309 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
8310}

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

8322 {
8323
8324 struct tm t0, t1;
8325
8326 t0.tm_year = 100;
8327 t0.tm_mon = 0;
8328 t0.tm_mday = 1;
8329 t0.tm_hour = 0;
8330 t0.tm_min = 0;
8331 t0.tm_sec = 0;
8332
8333 t1.tm_year = year - 1900;
8334 t1.tm_mon = mon - 1;
8335 t1.tm_mday = day;
8336 t1.tm_hour = hour;
8337 t1.tm_min = min;
8338 t1.tm_sec = sec;
8339
8340 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
8341}

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

8348 {
8349
8350 static char names[NTIMER][100], groups[NTIMER][100];
8351
8352 static double rt_name[NTIMER], rt_group[NTIMER],
8353 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
8354
8355 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
8356
8357 /* Get time... */
8358 t1 = omp_get_wtime();
8359 dt = t1 - t0;
8360
8361 /* Add elapsed time to current timers... */
8362 if (iname >= 0) {
8363 rt_name[iname] += dt;
8364 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
8365 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
8366 ct_name[iname]++;
8367 }
8368 if (igroup >= 0)
8369 rt_group[igroup] += t1 - t0;
8370
8371 /* Report timers... */
8372 if (output) {
8373 for (int i = 0; i < nname; i++)
8374 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
8375 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
8376 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
8377 for (int i = 0; i < ngroup; i++)
8378 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
8379 double total = 0.0;
8380 for (int i = 0; i < nname; i++)
8381 total += rt_name[i];
8382 LOG(1, "TIMER_TOTAL = %.3f s", total);
8383 }
8384
8385 /* Identify IDs of next timer... */
8386 for (iname = 0; iname < nname; iname++)
8387 if (strcasecmp(name, names[iname]) == 0)
8388 break;
8389 for (igroup = 0; igroup < ngroup; igroup++)
8390 if (strcasecmp(group, groups[igroup]) == 0)
8391 break;
8392
8393 /* Check whether this is a new timer... */
8394 if (iname >= nname) {
8395 sprintf(names[iname], "%s", name);
8396 if ((++nname) >= NTIMER)
8397 ERRMSG("Too many timers!");
8398 }
8399
8400 /* Check whether this is a new group... */
8401 if (igroup >= ngroup) {
8402 sprintf(groups[igroup], "%s", group);
8403 if ((++ngroup) >= NTIMER)
8404 ERRMSG("Too many groups!");
8405 }
8406
8407 /* Save starting time... */
8408 t0 = t1;
8409}
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:1945

◆ time_from_filename()

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

Extracts and converts a timestamp from a filename to Julian seconds.

The time_from_filename function parses a given filename to extract a timestamp and converts it to Julian seconds. The timestamp is expected to follow a specific format and position within the filename, defined by the offset parameter.

Parameters
filenameA string representing the filename containing the timestamp.
offsetAn integer indicating the position from the end of the filename where the timestamp starts.
Returns
The time in Julian seconds as a double.

The function performs the following steps:

  • Extracts the year, month, day, hour, and minute components of the timestamp from the filename using the given offset.
  • Validates the extracted components to ensure they represent a valid date and time.
  • Converts the validated date and time components to Julian seconds using the time2jsec function.
  • Returns the computed time in Julian seconds.
Note
The expected format of the timestamp in the filename is YYYY-MM-DD_HH-MM (e.g., "2023-05-27_14-45").
Warning
If the extracted components do not represent a valid date and time, the function will trigger an error message.
Author
Lars Hoffmann

Definition at line 8413 of file mptrac.c.

8415 {
8416
8417 char tstr[10];
8418
8419 double t;
8420
8421 /* Get time from filename... */
8422 int len = (int) strlen(filename);
8423 sprintf(tstr, "%.4s", &filename[len - offset]);
8424 int year = atoi(tstr);
8425 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
8426 int mon = atoi(tstr);
8427 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
8428 int day = atoi(tstr);
8429 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
8430 int hour = atoi(tstr);
8431 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
8432 int min = atoi(tstr);
8433
8434 /* Check time... */
8435 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
8436 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
8437 ERRMSG("Cannot read time from filename!");
8438
8439 /* Convert time to Julian seconds... */
8440 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
8441
8442 /* Return time... */
8443 return t;
8444}
Here is the call graph for this function:

◆ tropo_weight()

double tropo_weight ( const clim_t clim,
const double  t,
const double  lat,
const double  p 
)

Computes the weighting factor for a given pressure with respect to the tropopause.

The tropo_weight function calculates a weighting factor that indicates how much a given pressure p is influenced by the tropopause based on climatological data.

Parameters
climA pointer to a clim_t structure containing climatological tropopause data.
tThe time parameter, typically representing the time of year or specific temporal context.
latThe latitude for which the weighting factor is being calculated.
pThe pressure for which the weighting factor is to be computed.
Returns
A double representing the weighting factor.

The function performs the following steps:

  • Calculates the tropopause pressure pt using the clim_tropo function.
  • Determines the pressure range around the tropopause: p1 (lower bound) and p0 (upper bound).
  • Computes the weighting factor based on the given pressure p:
    • Returns 1 if p is greater than p0 (troposphere).
    • Returns 0 if p is less than p1 (stratosphere).
    • Linearly interpolates between 1 and 0 for pressures between p0 and p1.
Note
The clim_tropo function is assumed to provide the tropopause pressure based on climatological data.
The constants used in the pressure range calculation (0.866877899 and its reciprocal) are specific to the function's logic.
Author
Lars Hoffmann

Definition at line 8448 of file mptrac.c.

8452 {
8453
8454 /* Get tropopause pressure... */
8455 const double pt = clim_tropo(clim, t, lat);
8456
8457 /* Get pressure range... */
8458 const double p1 = pt * 0.866877899;
8459 const double p0 = pt / 0.866877899;
8460
8461 /* Get weighting factor... */
8462 if (p > p0)
8463 return 1;
8464 else if (p < p1)
8465 return 0;
8466 else
8467 return LIN(p0, 1.0, p1, 0.0, p);
8468}
Here is the call graph for this function:

◆ write_atm()

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

8476 {
8477
8478 /* Set timer... */
8479 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
8480
8481 /* Write info... */
8482 LOG(1, "Write atmospheric data: %s", filename);
8483
8484 /* Write ASCII data... */
8485 if (ctl->atm_type_out == 0)
8486 write_atm_asc(filename, ctl, atm, t);
8487
8488 /* Write binary data... */
8489 else if (ctl->atm_type_out == 1)
8490 write_atm_bin(filename, ctl, atm);
8491
8492 /* Write netCDF data... */
8493 else if (ctl->atm_type_out == 2)
8494 write_atm_nc(filename, ctl, atm);
8495
8496 /* Write CLaMS trajectory data... */
8497 else if (ctl->atm_type_out == 3)
8498 write_atm_clams_traj(filename, ctl, atm, t);
8499
8500 /* Write CLaMS pos data... */
8501 else if (ctl->atm_type_out == 4)
8502 write_atm_clams(filename, ctl, atm);
8503
8504 /* Error... */
8505 else
8506 ERRMSG("Atmospheric data type not supported!");
8507
8508 /* Write info... */
8509 double mini, maxi;
8510 LOG(2, "Number of particles: %d", atm->np);
8511 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
8512 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8513 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
8514 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
8515 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
8516 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
8517 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
8518 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
8519 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
8520 for (int iq = 0; iq < ctl->nq; iq++) {
8521 char msg[5 * LEN];
8522 sprintf(msg, "Quantity %s range: %s ... %s %s",
8523 ctl->qnt_name[iq], ctl->qnt_format[iq],
8524 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
8525 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
8526 LOG(2, msg, mini, maxi);
8527 }
8528}
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:8717
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:8532
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:8664
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:8614
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:8875
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 8532 of file mptrac.c.

8536 {
8537
8538 FILE *out;
8539
8540 /* Set time interval for output... */
8541 const double t0 = t - 0.5 * ctl->dt_mod;
8542 const double t1 = t + 0.5 * ctl->dt_mod;
8543
8544 /* Check if gnuplot output is requested... */
8545 if (ctl->atm_gpfile[0] != '-') {
8546
8547 /* Create gnuplot pipe... */
8548 if (!(out = popen("gnuplot", "w")))
8549 ERRMSG("Cannot create pipe to gnuplot!");
8550
8551 /* Set plot filename... */
8552 fprintf(out, "set out \"%s.png\"\n", filename);
8553
8554 /* Set time string... */
8555 double r;
8556 int year, mon, day, hour, min, sec;
8557 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
8558 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
8559 year, mon, day, hour, min);
8560
8561 /* Dump gnuplot file to pipe... */
8562 FILE *in;
8563 if (!(in = fopen(ctl->atm_gpfile, "r")))
8564 ERRMSG("Cannot open file!");
8565 char line[LEN];
8566 while (fgets(line, LEN, in))
8567 fprintf(out, "%s", line);
8568 fclose(in);
8569 }
8570
8571 else {
8572
8573 /* Create file... */
8574 if (!(out = fopen(filename, "w")))
8575 ERRMSG("Cannot create file!");
8576 }
8577
8578 /* Write header... */
8579 fprintf(out,
8580 "# $1 = time [s]\n"
8581 "# $2 = altitude [km]\n"
8582 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
8583 for (int iq = 0; iq < ctl->nq; iq++)
8584 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
8585 ctl->qnt_unit[iq]);
8586 fprintf(out, "\n");
8587
8588 /* Write data... */
8589 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
8590
8591 /* Check time... */
8592 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
8593 continue;
8594
8595 /* Write output... */
8596 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
8597 atm->lon[ip], atm->lat[ip]);
8598 for (int iq = 0; iq < ctl->nq; iq++) {
8599 fprintf(out, " ");
8600 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
8601 fprintf(out, ctl->qnt_format[iq], NAN);
8602 else
8603 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
8604 }
8605 fprintf(out, "\n");
8606 }
8607
8608 /* Close file... */
8609 fclose(out);
8610}
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 8614 of file mptrac.c.

8617 {
8618
8619 FILE *out;
8620
8621 /* Create file... */
8622 if (!(out = fopen(filename, "w")))
8623 ERRMSG("Cannot create file!");
8624
8625 /* Write version of binary data... */
8626 int version = 100;
8627 FWRITE(&version, int,
8628 1,
8629 out);
8630
8631 /* Write data... */
8632 FWRITE(&atm->np, int,
8633 1,
8634 out);
8635 FWRITE(atm->time, double,
8636 (size_t) atm->np,
8637 out);
8638 FWRITE(atm->p, double,
8639 (size_t) atm->np,
8640 out);
8641 FWRITE(atm->lon, double,
8642 (size_t) atm->np,
8643 out);
8644 FWRITE(atm->lat, double,
8645 (size_t) atm->np,
8646 out);
8647 for (int iq = 0; iq < ctl->nq; iq++)
8648 FWRITE(atm->q[iq], double,
8649 (size_t) atm->np,
8650 out);
8651
8652 /* Write final flag... */
8653 int final = 999;
8654 FWRITE(&final, int,
8655 1,
8656 out);
8657
8658 /* Close file... */
8659 fclose(out);
8660}

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

8667 {
8668
8669 int tid, pid, ncid, varid;
8670 size_t start[2], count[2];
8671
8672 /* Create file... */
8673 nc_create(filename, NC_NETCDF4, &ncid);
8674
8675 /* Define dimensions... */
8676 NC(nc_def_dim(ncid, "time", 1, &tid));
8677 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
8678
8679 /* Define variables and their attributes... */
8680 int dim_ids[2] = { tid, pid };
8681 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
8682 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
8683 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
8684 ctl->atm_nc_level, 0);
8685 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
8686 ctl->atm_nc_level, 0);
8687 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
8688 ctl->atm_nc_level, 0);
8689 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
8690 for (int iq = 0; iq < ctl->nq; iq++)
8691 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
8692 ctl->qnt_name[iq], ctl->qnt_unit[iq],
8693 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
8694
8695 /* Define global attributes... */
8696 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
8697 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
8698
8699 /* End definitions... */
8700 NC(nc_enddef(ncid));
8701
8702 /* Write data... */
8703 NC_PUT_DOUBLE("time", atm->time, 0);
8704 NC_PUT_DOUBLE("LAT", atm->lat, 0);
8705 NC_PUT_DOUBLE("LON", atm->lon, 0);
8706 NC_PUT_DOUBLE("PRESS", atm->p, 0);
8707 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
8708 for (int iq = 0; iq < ctl->nq; iq++)
8709 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8710
8711 /* Close file... */
8712 NC(nc_close(ncid));
8713}
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1197
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1030
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1111

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

8721 {
8722
8723 /* Global Counter... */
8724 static size_t out_cnt = 0;
8725
8726 double r, r_start, r_stop;
8727 int year, mon, day, hour, min, sec;
8728 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
8729 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
8730 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
8731
8732 int ncid, varid, tid, pid, cid;
8733 int dim_ids[2];
8734
8735 /* time, nparc */
8736 size_t start[2];
8737 size_t count[2];
8738
8739 /* Determine start and stop times of calculation... */
8740 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
8741 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
8742 &min_start, &sec_start, &r_start);
8743 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
8744 &min_stop, &sec_stop, &r_stop);
8745
8746 sprintf(filename_out, "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc",
8747 dirname,
8748 year_start % 100, mon_start, day_start, hour_start,
8749 year_stop % 100, mon_stop, day_stop, hour_stop);
8750 LOG(1, "Write traj file: %s", filename_out);
8751
8752 /* Define hyperslap for the traj_file... */
8753 start[0] = out_cnt;
8754 start[1] = 0;
8755 count[0] = 1;
8756 count[1] = (size_t) atm->np;
8757
8758 /* Create the file at the first timestep... */
8759 if (out_cnt == 0) {
8760
8761 /* Create file... */
8762 nc_create(filename_out, NC_NETCDF4, &ncid);
8763
8764 /* Define dimensions... */
8765 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
8766 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
8767 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
8768 dim_ids[0] = tid;
8769 dim_ids[1] = pid;
8770
8771 /* Define variables and their attributes... */
8772 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
8773 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
8774 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
8775 ctl->atm_nc_level, 0);
8776 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
8777 ctl->atm_nc_level, 0);
8778 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
8779 ctl->atm_nc_level, 0);
8780 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
8781 ctl->atm_nc_level, 0);
8782 for (int iq = 0; iq < ctl->nq; iq++)
8783 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
8784 ctl->qnt_name[iq], ctl->qnt_unit[iq],
8785 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
8786
8787 /* Define global attributes... */
8788 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
8789 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
8790
8791 /* End definitions... */
8792 NC(nc_enddef(ncid));
8793 NC(nc_close(ncid));
8794 }
8795
8796 /* Increment global counter to change hyperslap... */
8797 out_cnt++;
8798
8799 /* Open file... */
8800 NC(nc_open(filename_out, NC_WRITE, &ncid));
8801
8802 /* Write data... */
8803 NC_PUT_DOUBLE("time", atm->time, 1);
8804 NC_PUT_DOUBLE("LAT", atm->lat, 1);
8805 NC_PUT_DOUBLE("LON", atm->lon, 1);
8806 NC_PUT_DOUBLE("PRESS", atm->p, 1);
8807 if (ctl->advect_vert_coord == 1) {
8808 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
8809 } else if (ctl->qnt_zeta >= 0) {
8810 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
8811 }
8812 for (int iq = 0; iq < ctl->nq; iq++)
8813 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
8814
8815 /* Close file... */
8816 NC(nc_close(ncid));
8817
8818 /* At the last time step create the init_fix_YYYYMMDDHH file... */
8819 if ((year == year_stop) && (mon == mon_stop)
8820 && (day == day_stop) && (hour == hour_stop)) {
8821
8822 /* Set filename... */
8823 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
8824 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
8825 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
8826 LOG(1, "Write init file: %s", filename_init);
8827
8828 /* Create file... */
8829 nc_create(filename_init, NC_NETCDF4, &ncid);
8830
8831 /* Define dimensions... */
8832 NC(nc_def_dim(ncid, "time", 1, &tid));
8833 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
8834 dim_ids[0] = tid;
8835 dim_ids[1] = pid;
8836
8837 /* Define variables and their attributes... */
8838 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
8839 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
8840 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
8841 ctl->atm_nc_level, 0);
8842 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
8843 ctl->atm_nc_level, 0);
8844 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
8845 ctl->atm_nc_level, 0);
8846 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
8847 for (int iq = 0; iq < ctl->nq; iq++)
8848 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
8849 ctl->qnt_name[iq], ctl->qnt_unit[iq],
8850 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
8851
8852 /* Define global attributes... */
8853 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
8854 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
8855
8856 /* End definitions... */
8857 NC(nc_enddef(ncid));
8858
8859 /* Write data... */
8860 NC_PUT_DOUBLE("time", atm->time, 0);
8861 NC_PUT_DOUBLE("LAT", atm->lat, 0);
8862 NC_PUT_DOUBLE("LON", atm->lon, 0);
8863 NC_PUT_DOUBLE("PRESS", atm->p, 0);
8864 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
8865 for (int iq = 0; iq < ctl->nq; iq++)
8866 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8867
8868 /* Close file... */
8869 NC(nc_close(ncid));
8870 }
8871}
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 8875 of file mptrac.c.

8878 {
8879
8880 int ncid, obsid, varid;
8881
8882 size_t start[2], count[2];
8883
8884 /* Create file... */
8885 NC(nc_create(filename, NC_NETCDF4, &ncid));
8886
8887 /* Define dimensions... */
8888 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
8889
8890 /* Define variables and their attributes... */
8891 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
8892 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
8893 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
8894 ctl->atm_nc_level, 0);
8895 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
8896 ctl->atm_nc_level, 0);
8897 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
8898 ctl->atm_nc_level, 0);
8899 for (int iq = 0; iq < ctl->nq; iq++)
8900 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
8901 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
8902 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
8903
8904 /* Define global attributes... */
8905 NC_PUT_ATT_GLOBAL("featureType", "point");
8906
8907 /* End definitions... */
8908 NC(nc_enddef(ncid));
8909
8910 /* Write data... */
8911 NC_PUT_DOUBLE("time", atm->time, 0);
8912 NC_PUT_DOUBLE("press", atm->p, 0);
8913 NC_PUT_DOUBLE("lon", atm->lon, 0);
8914 NC_PUT_DOUBLE("lat", atm->lat, 0);
8915 for (int iq = 0; iq < ctl->nq; iq++)
8916 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8917
8918 /* Close file... */
8919 NC(nc_close(ncid));
8920}

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

8928 {
8929
8930 static FILE *out;
8931
8932 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
8933 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
8934
8935 static int *obscount, ct, cx, cy, cz, ip, ix, iy, iz, n, nobs, nk;
8936
8937 /* Set timer... */
8938 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
8939
8940 /* Init... */
8941 if (t == ctl->t_start) {
8942
8943 /* Check quantity index for mass... */
8944 if (ctl->qnt_m < 0)
8945 ERRMSG("Need quantity mass!");
8946
8947 /* Allocate... */
8948 ALLOC(area, double,
8949 ctl->csi_ny);
8950 ALLOC(rt, double,
8951 NOBS);
8952 ALLOC(rz, double,
8953 NOBS);
8954 ALLOC(rlon, double,
8955 NOBS);
8956 ALLOC(rlat, double,
8957 NOBS);
8958 ALLOC(robs, double,
8959 NOBS);
8960
8961 /* Read observation data... */
8962 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
8963
8964 /* Read kernel data... */
8965 if (ctl->csi_kernel[0] != '-')
8966 read_kernel(ctl->csi_kernel, kz, kw, &nk);
8967
8968 /* Create new file... */
8969 LOG(1, "Write CSI data: %s", filename);
8970 if (!(out = fopen(filename, "w")))
8971 ERRMSG("Cannot create file!");
8972
8973 /* Write header... */
8974 fprintf(out,
8975 "# $1 = time [s]\n"
8976 "# $2 = number of hits (cx)\n"
8977 "# $3 = number of misses (cy)\n"
8978 "# $4 = number of false alarms (cz)\n"
8979 "# $5 = number of observations (cx + cy)\n"
8980 "# $6 = number of forecasts (cx + cz)\n"
8981 "# $7 = bias (ratio of forecasts and observations) [%%]\n"
8982 "# $8 = probability of detection (POD) [%%]\n"
8983 "# $9 = false alarm rate (FAR) [%%]\n"
8984 "# $10 = critical success index (CSI) [%%]\n");
8985 fprintf(out,
8986 "# $11 = hits associated with random chance\n"
8987 "# $12 = equitable threat score (ETS) [%%]\n"
8988 "# $13 = Pearson linear correlation coefficient\n"
8989 "# $14 = Spearman rank-order correlation coefficient\n"
8990 "# $15 = column density mean error (F - O) [kg/m^2]\n"
8991 "# $16 = column density root mean square error (RMSE) [kg/m^2]\n"
8992 "# $17 = column density mean absolute error [kg/m^2]\n"
8993 "# $18 = log-likelihood function\n"
8994 "# $19 = number of data points\n\n");
8995
8996 /* Set grid box size... */
8997 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
8998 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
8999 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
9000
9001 /* Set horizontal coordinates... */
9002 for (iy = 0; iy < ctl->csi_ny; iy++) {
9003 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
9004 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat));
9005 }
9006 }
9007
9008 /* Set time interval... */
9009 const double t0 = t - 0.5 * ctl->dt_mod;
9010 const double t1 = t + 0.5 * ctl->dt_mod;
9011
9012 /* Allocate... */
9013 ALLOC(modmean, double,
9014 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9015 ALLOC(obsmean, double,
9016 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9017 ALLOC(obscount, int,
9018 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9019 ALLOC(obsstd, double,
9020 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9021
9022 /* Loop over observations... */
9023 for (int i = 0; i < nobs; i++) {
9024
9025 /* Check time... */
9026 if (rt[i] < t0)
9027 continue;
9028 else if (rt[i] >= t1)
9029 break;
9030
9031 /* Check observation data... */
9032 if (!isfinite(robs[i]))
9033 continue;
9034
9035 /* Calculate indices... */
9036 ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
9037 iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
9038 iz = (int) ((rz[i] - ctl->csi_z0) / dz);
9039
9040 /* Check indices... */
9041 if (ix < 0 || ix >= ctl->csi_nx ||
9042 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9043 continue;
9044
9045 /* Get mean observation index... */
9046 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9047 obsmean[idx] += robs[i];
9048 obsstd[idx] += SQR(robs[i]);
9049 obscount[idx]++;
9050 }
9051
9052 /* Analyze model data... */
9053 for (ip = 0; ip < atm->np; ip++) {
9054
9055 /* Check time... */
9056 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9057 continue;
9058
9059 /* Get indices... */
9060 ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
9061 iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
9062 iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
9063
9064 /* Check indices... */
9065 if (ix < 0 || ix >= ctl->csi_nx ||
9066 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9067 continue;
9068
9069 /* Get total mass in grid cell... */
9070 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9071 modmean[idx] += kernel_weight(kz, kw, nk, atm->p[ip])
9072 * atm->q[ctl->qnt_m][ip];
9073 }
9074
9075 /* Analyze all grid cells... */
9076 for (ix = 0; ix < ctl->csi_nx; ix++)
9077 for (iy = 0; iy < ctl->csi_ny; iy++)
9078 for (iz = 0; iz < ctl->csi_nz; iz++) {
9079
9080 /* Calculate mean observation index... */
9081 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9082 if (obscount[idx] > 0) {
9083 obsmean[idx] /= obscount[idx];
9084 obsstd[idx] -= SQR(obsmean[idx]);
9085 obsstd[idx] = sqrt(obsstd[idx]);
9086 }
9087
9088 /* Calculate column density... */
9089 if (modmean[idx] > 0)
9090 modmean[idx] /= (1e6 * area[iy]);
9091
9092 /* Calculate CSI... */
9093 if (obscount[idx] > 0) {
9094 ct++;
9095 if (obsmean[idx] >= ctl->csi_obsmin &&
9096 modmean[idx] >= ctl->csi_modmin)
9097 cx++;
9098 else if (obsmean[idx] >= ctl->csi_obsmin &&
9099 modmean[idx] < ctl->csi_modmin)
9100 cy++;
9101 else if (obsmean[idx] < ctl->csi_obsmin &&
9102 modmean[idx] >= ctl->csi_modmin)
9103 cz++;
9104 }
9105
9106 /* Save data for other verification statistics... */
9107 if (obscount[idx] > 0
9108 && (obsmean[idx] >= ctl->csi_obsmin
9109 || modmean[idx] >= ctl->csi_modmin)) {
9110 x[n] = modmean[idx];
9111 y[n] = obsmean[idx];
9112 if (modmean[idx] >= ctl->csi_modmin)
9113 obsstdn[n] = obsstd[idx];
9114 if ((++n) >= NCSI)
9115 ERRMSG("Too many data points to calculate statistics!");
9116 }
9117 }
9118
9119 /* Write output... */
9120 if (fmod(t, ctl->csi_dt_out) == 0) {
9121
9122 /* Calculate verification statistics
9123 (https://www.cawcr.gov.au/projects/verification/) ... */
9124 static double work[2 * NCSI], work2[2 * NCSI];;
9125 const int n_obs = cx + cy;
9126 const int n_for = cx + cz;
9127 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
9128 const double pod = (n_obs > 0) ? (100. * cx) / n_obs : NAN;
9129 const double far = (n_for > 0) ? (100. * cz) / n_for : NAN;
9130 const double csi =
9131 (cx + cy + cz > 0) ? (100. * cx) / (cx + cy + cz) : NAN;
9132 const double cx_rd = (ct > 0) ? (1. * n_obs * n_for) / ct : NAN;
9133 const double ets = (cx + cy + cz - cx_rd > 0) ?
9134 (100. * (cx - cx_rd)) / (cx + cy + cz - cx_rd) : NAN;
9135 const double rho_p =
9136 (n > 0) ? gsl_stats_correlation(x, 1, y, 1, (size_t) n) : NAN;
9137 const double rho_s =
9138 (n > 0) ? gsl_stats_spearman(x, 1, y, 1, (size_t) n, work) : NAN;
9139 for (int i = 0; i < n; i++) {
9140 work[i] = x[i] - y[i];
9141 work2[i] = (obsstdn[i] != 0) ? (x[i] - y[i]) / obsstdn[i] : 0;
9142 }
9143 const double mean = (n > 0) ? gsl_stats_mean(work, 1, (size_t) n) : NAN;
9144 const double rmse =
9145 (n > 0) ? gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n,
9146 0.0) : NAN;
9147 const double absdev =
9148 (n > 0) ? gsl_stats_absdev_m(work, 1, (size_t) n, 0.0) : NAN;
9149 const double loglikelihood =
9150 (n > 0) ? gsl_stats_tss(work2, 1, (size_t) n) * (-0.5) : GSL_NAN;
9151
9152 /* Write... */
9153 fprintf(out,
9154 "%.2f %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n", t,
9155 cx, cy, cz, n_obs, n_for, bias, pod, far, csi, cx_rd, ets, rho_p,
9156 rho_s, mean, rmse, absdev, loglikelihood, n);
9157
9158 /* Set counters to zero... */
9159 n = ct = cx = cy = cz = 0;
9160 }
9161
9162 /* Free... */
9163 free(modmean);
9164 free(obsmean);
9165 free(obscount);
9166 free(obsstd);
9167
9168 /* Finalize... */
9169 if (t == ctl->t_stop) {
9170
9171 /* Close output file... */
9172 fclose(out);
9173
9174 /* Free... */
9175 free(area);
9176 free(rt);
9177 free(rz);
9178 free(rlon);
9179 free(rlat);
9180 free(robs);
9181 }
9182}
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:7997
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:5614
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:1865
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:251
integer, parameter ct
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 9186 of file mptrac.c.

9190 {
9191
9192 static FILE *out;
9193
9194 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
9195 x[3], zm[NENS];
9196
9197 static int n[NENS];
9198
9199 /* Set timer... */
9200 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
9201
9202 /* Check quantities... */
9203 if (ctl->qnt_ens < 0)
9204 ERRMSG("Missing ensemble IDs!");
9205
9206 /* Set time interval... */
9207 const double t0 = t - 0.5 * ctl->dt_mod;
9208 const double t1 = t + 0.5 * ctl->dt_mod;
9209
9210 /* Init... */
9211 for (int i = 0; i < NENS; i++) {
9212 for (int iq = 0; iq < ctl->nq; iq++)
9213 qm[iq][i] = qs[iq][i] = 0;
9214 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
9215 n[i] = 0;
9216 }
9217
9218 /* Loop over air parcels... */
9219 for (int ip = 0; ip < atm->np; ip++) {
9220
9221 /* Check time... */
9222 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9223 continue;
9224
9225 /* Check ensemble ID... */
9226 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
9227 ERRMSG("Ensemble ID is out of range!");
9228
9229 /* Get means... */
9230 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
9231 for (int iq = 0; iq < ctl->nq; iq++) {
9232 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
9233 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
9234 }
9235 xm[ctl->qnt_ens][0] += x[0];
9236 xm[ctl->qnt_ens][1] += x[1];
9237 xm[ctl->qnt_ens][2] += x[2];
9238 zm[ctl->qnt_ens] += Z(atm->p[ip]);
9239 n[ctl->qnt_ens]++;
9240 }
9241
9242 /* Create file... */
9243 LOG(1, "Write ensemble data: %s", filename);
9244 if (!(out = fopen(filename, "w")))
9245 ERRMSG("Cannot create file!");
9246
9247 /* Write header... */
9248 fprintf(out,
9249 "# $1 = time [s]\n"
9250 "# $2 = altitude [km]\n"
9251 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
9252 for (int iq = 0; iq < ctl->nq; iq++)
9253 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
9254 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9255 for (int iq = 0; iq < ctl->nq; iq++)
9256 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
9257 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9258 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
9259
9260 /* Write data... */
9261 for (int i = 0; i < NENS; i++)
9262 if (n[i] > 0) {
9263 cart2geo(xm[i], &dummy, &lon, &lat);
9264 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
9265 for (int iq = 0; iq < ctl->nq; iq++) {
9266 fprintf(out, " ");
9267 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
9268 }
9269 for (int iq = 0; iq < ctl->nq; iq++) {
9270 fprintf(out, " ");
9271 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
9272 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
9273 }
9274 fprintf(out, " %d\n", n[i]);
9275 }
9276
9277 /* Close file... */
9278 fclose(out);
9279}
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:274
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 9283 of file mptrac.c.

9289 {
9290
9291 static double kz[EP], kw[EP];
9292
9293 static int nk;
9294
9295 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
9296
9297 int *ixs, *iys, *izs, *np;
9298
9299 /* Set timer... */
9300 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
9301
9302 /* Write info... */
9303 LOG(1, "Write grid data: %s", filename);
9304
9305 /* Init... */
9306 if (t == ctl->t_start) {
9307
9308 /* Read kernel data... */
9309 if (ctl->grid_kernel[0] != '-')
9310 read_kernel(ctl->grid_kernel, kz, kw, &nk);
9311 }
9312
9313 /* Allocate... */
9314 ALLOC(cd, double,
9315 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9316 for (int iq = 0; iq < ctl->nq; iq++) {
9317 ALLOC(mean[iq], double,
9318 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9319 ALLOC(sigma[iq], double,
9320 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9321 }
9322 ALLOC(vmr_impl, double,
9323 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9324 ALLOC(z, double,
9325 ctl->grid_nz);
9326 ALLOC(lon, double,
9327 ctl->grid_nx);
9328 ALLOC(lat, double,
9329 ctl->grid_ny);
9330 ALLOC(area, double,
9331 ctl->grid_ny);
9332 ALLOC(press, double,
9333 ctl->grid_nz);
9334 ALLOC(np, int,
9335 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9336 ALLOC(ixs, int,
9337 atm->np);
9338 ALLOC(iys, int,
9339 atm->np);
9340 ALLOC(izs, int,
9341 atm->np);
9342
9343 /* Set grid box size... */
9344 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
9345 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
9346 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
9347
9348 /* Set vertical coordinates... */
9349#pragma omp parallel for default(shared)
9350 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9351 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
9352 press[iz] = P(z[iz]);
9353 }
9354
9355 /* Set horizontal coordinates... */
9356 for (int ix = 0; ix < ctl->grid_nx; ix++)
9357 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
9358#pragma omp parallel for default(shared)
9359 for (int iy = 0; iy < ctl->grid_ny; iy++) {
9360 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
9361 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
9362 }
9363
9364 /* Set time interval for output... */
9365 const double t0 = t - 0.5 * ctl->dt_mod;
9366 const double t1 = t + 0.5 * ctl->dt_mod;
9367
9368 /* Get grid box indices... */
9369#pragma omp parallel for default(shared)
9370 for (int ip = 0; ip < atm->np; ip++) {
9371 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
9372 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
9373 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
9374 if (atm->time[ip] < t0 || atm->time[ip] > t1
9375 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
9376 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
9377 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
9378 izs[ip] = -1;
9379 }
9380
9381 /* Average data... */
9382 for (int ip = 0; ip < atm->np; ip++)
9383 if (izs[ip] >= 0) {
9384 int idx =
9385 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
9386 double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
9387 np[idx]++;
9388 for (int iq = 0; iq < ctl->nq; iq++) {
9389 mean[iq][idx] += kernel * atm->q[iq][ip];
9390 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
9391 }
9392 }
9393
9394 /* Calculate column density and volume mixing ratio... */
9395#pragma omp parallel for default(shared)
9396 for (int ix = 0; ix < ctl->grid_nx; ix++)
9397 for (int iy = 0; iy < ctl->grid_ny; iy++)
9398 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9399
9400 /* Get grid index... */
9401 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
9402
9403 /* Calculate column density... */
9404 cd[idx] = NAN;
9405 if (ctl->qnt_m >= 0)
9406 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
9407
9408 /* Calculate volume mixing ratio (implicit)... */
9409 vmr_impl[idx] = NAN;
9410 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
9411 && met1 != NULL) {
9412 vmr_impl[idx] = 0;
9413 if (mean[ctl->qnt_m][idx] > 0) {
9414
9415 /* Get temperature... */
9416 double temp;
9418 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
9419 lon[ix], lat[iy], &temp, ci, cw, 1);
9420
9421 /* Calculate volume mixing ratio... */
9422 vmr_impl[idx] = MA / ctl->molmass * mean[ctl->qnt_m][idx]
9423 / (RHO(press[iz], temp) * 1e6 * area[iy] * 1e3 * dz);
9424 }
9425 }
9426
9427 /* Calculate mean... */
9428 if (np[idx] > 0)
9429 for (int iq = 0; iq < ctl->nq; iq++) {
9430 mean[iq][idx] /= np[idx];
9431 double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
9432 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
9433 } else
9434 for (int iq = 0; iq < ctl->nq; iq++) {
9435 mean[iq][idx] = NAN;
9436 sigma[iq][idx] = NAN;
9437 }
9438 }
9439
9440 /* Write ASCII data... */
9441 if (ctl->grid_type == 0)
9442 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
9443 t, z, lon, lat, area, dz, np);
9444
9445 /* Write netCDF data... */
9446 else if (ctl->grid_type == 1)
9447 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
9448 t, z, lon, lat, area, dz, np);
9449
9450 /* Error message... */
9451 else
9452 ERRMSG("Grid data format GRID_TYPE unknown!");
9453
9454 /* Free... */
9455 free(cd);
9456 for (int iq = 0; iq < ctl->nq; iq++) {
9457 free(mean[iq]);
9458 free(sigma[iq]);
9459 }
9460 free(vmr_impl);
9461 free(z);
9462 free(lon);
9463 free(lat);
9464 free(area);
9465 free(press);
9466 free(np);
9467 free(ixs);
9468 free(iys);
9469 free(izs);
9470}
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:9474
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:9578
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 9474 of file mptrac.c.

9487 {
9488
9489 FILE *out;
9490
9491 /* Check if gnuplot output is requested... */
9492 if (ctl->grid_gpfile[0] != '-') {
9493
9494 /* Create gnuplot pipe... */
9495 if (!(out = popen("gnuplot", "w")))
9496 ERRMSG("Cannot create pipe to gnuplot!");
9497
9498 /* Set plot filename... */
9499 fprintf(out, "set out \"%s.png\"\n", filename);
9500
9501 /* Set time string... */
9502 double r;
9503 int year, mon, day, hour, min, sec;
9504 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9505 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
9506 year, mon, day, hour, min);
9507
9508 /* Dump gnuplot file to pipe... */
9509 FILE *in;
9510 char line[LEN];
9511 if (!(in = fopen(ctl->grid_gpfile, "r")))
9512 ERRMSG("Cannot open file!");
9513 while (fgets(line, LEN, in))
9514 fprintf(out, "%s", line);
9515 fclose(in);
9516 }
9517
9518 else {
9519
9520 /* Create file... */
9521 if (!(out = fopen(filename, "w")))
9522 ERRMSG("Cannot create file!");
9523 }
9524
9525 /* Write header... */
9526 fprintf(out,
9527 "# $1 = time [s]\n"
9528 "# $2 = altitude [km]\n"
9529 "# $3 = longitude [deg]\n"
9530 "# $4 = latitude [deg]\n"
9531 "# $5 = surface area [km^2]\n"
9532 "# $6 = layer depth [km]\n"
9533 "# $7 = column density (implicit) [kg/m^2]\n"
9534 "# $8 = volume mixing ratio (implicit) [ppv]\n"
9535 "# $9 = number of particles [1]\n");
9536 for (int iq = 0; iq < ctl->nq; iq++)
9537 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
9538 ctl->qnt_unit[iq]);
9539 if (ctl->grid_stddev)
9540 for (int iq = 0; iq < ctl->nq; iq++)
9541 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
9542 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9543 fprintf(out, "\n");
9544
9545 /* Write data... */
9546 for (int ix = 0; ix < ctl->grid_nx; ix++) {
9547 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
9548 fprintf(out, "\n");
9549 for (int iy = 0; iy < ctl->grid_ny; iy++) {
9550 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
9551 fprintf(out, "\n");
9552 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9553 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
9554 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
9555 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
9556 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
9557 for (int iq = 0; iq < ctl->nq; iq++) {
9558 fprintf(out, " ");
9559 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
9560 }
9561 if (ctl->grid_stddev)
9562 for (int iq = 0; iq < ctl->nq; iq++) {
9563 fprintf(out, " ");
9564 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
9565 }
9566 fprintf(out, "\n");
9567 }
9568 }
9569 }
9570 }
9571
9572 /* Close file... */
9573 fclose(out);
9574}
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 9578 of file mptrac.c.

9591 {
9592
9593 char longname[2 * LEN], varname[2 * LEN];
9594
9595 double *help;
9596
9597 int *help2, ncid, dimid[10], varid;
9598
9599 size_t start[2], count[2];
9600
9601 /* Allocate... */
9602 ALLOC(help, double,
9603 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9604 ALLOC(help2, int,
9605 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9606
9607 /* Create file... */
9608 NC(nc_create(filename, NC_NETCDF4, &ncid));
9609
9610 /* Define dimensions... */
9611 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
9612 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
9613 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
9614 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
9615 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
9616
9617 /* Define variables and their attributes... */
9618 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
9619 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
9620 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
9621 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
9622 0);
9623 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
9624 0);
9625 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
9626 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
9627
9628 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
9629 ctl->grid_nc_level, 0);
9630 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid, "volume mixing ratio (implicit)",
9631 "ppv", ctl->grid_nc_level, 0);
9632 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
9633 for (int iq = 0; iq < ctl->nq; iq++) {
9634 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
9635 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
9636 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
9637 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
9638 if (ctl->grid_stddev) {
9639 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
9640 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
9641 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
9642 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
9643 }
9644 }
9645 /* End definitions... */
9646 NC(nc_enddef(ncid));
9647
9648 /* Write data... */
9649 NC_PUT_DOUBLE("time", &t, 0);
9650 NC_PUT_DOUBLE("lon", lon, 0);
9651 NC_PUT_DOUBLE("lat", lat, 0);
9652 NC_PUT_DOUBLE("z", z, 0);
9653 NC_PUT_DOUBLE("area", area, 0);
9654 NC_PUT_DOUBLE("dz", &dz, 0);
9655
9656 for (int ix = 0; ix < ctl->grid_nx; ix++)
9657 for (int iy = 0; iy < ctl->grid_ny; iy++)
9658 for (int iz = 0; iz < ctl->grid_nz; iz++)
9659 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9660 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9661 NC_PUT_DOUBLE("cd", help, 0);
9662
9663 for (int ix = 0; ix < ctl->grid_nx; ix++)
9664 for (int iy = 0; iy < ctl->grid_ny; iy++)
9665 for (int iz = 0; iz < ctl->grid_nz; iz++)
9666 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9667 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9668 NC_PUT_DOUBLE("vmr_impl", help, 0);
9669
9670 for (int ix = 0; ix < ctl->grid_nx; ix++)
9671 for (int iy = 0; iy < ctl->grid_ny; iy++)
9672 for (int iz = 0; iz < ctl->grid_nz; iz++)
9673 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9674 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9675 NC_PUT_INT("np", help2, 0);
9676
9677 for (int iq = 0; iq < ctl->nq; iq++) {
9678 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
9679 for (int ix = 0; ix < ctl->grid_nx; ix++)
9680 for (int iy = 0; iy < ctl->grid_ny; iy++)
9681 for (int iz = 0; iz < ctl->grid_nz; iz++)
9682 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9683 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9684 NC_PUT_DOUBLE(varname, help, 0);
9685 }
9686
9687 if (ctl->grid_stddev)
9688 for (int iq = 0; iq < ctl->nq; iq++) {
9689 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
9690 for (int ix = 0; ix < ctl->grid_nx; ix++)
9691 for (int iy = 0; iy < ctl->grid_ny; iy++)
9692 for (int iz = 0; iz < ctl->grid_nz; iz++)
9693 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9694 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9695 NC_PUT_DOUBLE(varname, help, 0);
9696 }
9697
9698 /* Close file... */
9699 NC(nc_close(ncid));
9700
9701 /* Free... */
9702 free(help);
9703 free(help2);
9704}
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1158

◆ write_met()

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

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

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

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

Definition at line 9708 of file mptrac.c.

9711 {
9712
9713 /* Set timer... */
9714 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
9715
9716 /* Write info... */
9717 LOG(1, "Write meteo data: %s", filename);
9718
9719 /* Check compression flags... */
9720#ifndef ZFP
9721 if (ctl->met_type == 3)
9722 ERRMSG("MPTRAC was compiled without zfp compression!");
9723#endif
9724#ifndef ZSTD
9725 if (ctl->met_type == 4)
9726 ERRMSG("MPTRAC was compiled without zstd compression!");
9727#endif
9728#ifndef CMS
9729 if (ctl->met_type == 5)
9730 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
9731#endif
9732
9733 /* Write netCDF data... */
9734 if (ctl->met_type == 0)
9735 write_met_nc(filename, ctl, met);
9736
9737 /* Write binary data... */
9738 else if (ctl->met_type >= 1 && ctl->met_type <= 5)
9739 write_met_bin(filename, ctl, met);
9740
9741 /* Not implemented... */
9742 else
9743 ERRMSG("MET_TYPE not implemented!");
9744}
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:9950
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:9748
Here is the call graph for this function:

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

9751 {
9752
9753 /* Create file... */
9754 FILE *out;
9755 if (!(out = fopen(filename, "w")))
9756 ERRMSG("Cannot create file!");
9757
9758 /* Write type of binary data... */
9759 FWRITE(&ctl->met_type, int,
9760 1,
9761 out);
9762
9763 /* Write version of binary data... */
9764 int version = 102;
9765 FWRITE(&version, int,
9766 1,
9767 out);
9768
9769 /* Write grid data... */
9770 FWRITE(&met->time, double,
9771 1,
9772 out);
9773 FWRITE(&met->nx, int,
9774 1,
9775 out);
9776 FWRITE(&met->ny, int,
9777 1,
9778 out);
9779 FWRITE(&met->np, int,
9780 1,
9781 out);
9782 FWRITE(met->lon, double,
9783 (size_t) met->nx,
9784 out);
9785 FWRITE(met->lat, double,
9786 (size_t) met->ny,
9787 out);
9788 FWRITE(met->p, double,
9789 (size_t) met->np,
9790 out);
9791
9792 /* Write surface data... */
9793 write_met_bin_2d(out, met, met->ps, "PS");
9794 write_met_bin_2d(out, met, met->ts, "TS");
9795 write_met_bin_2d(out, met, met->zs, "ZS");
9796 write_met_bin_2d(out, met, met->us, "US");
9797 write_met_bin_2d(out, met, met->vs, "VS");
9798 write_met_bin_2d(out, met, met->lsm, "LSM");
9799 write_met_bin_2d(out, met, met->sst, "SST");
9800 write_met_bin_2d(out, met, met->pbl, "PBL");
9801 write_met_bin_2d(out, met, met->pt, "PT");
9802 write_met_bin_2d(out, met, met->tt, "TT");
9803 write_met_bin_2d(out, met, met->zt, "ZT");
9804 write_met_bin_2d(out, met, met->h2ot, "H2OT");
9805 write_met_bin_2d(out, met, met->pct, "PCT");
9806 write_met_bin_2d(out, met, met->pcb, "PCB");
9807 write_met_bin_2d(out, met, met->cl, "CL");
9808 write_met_bin_2d(out, met, met->plcl, "PLCL");
9809 write_met_bin_2d(out, met, met->plfc, "PLFC");
9810 write_met_bin_2d(out, met, met->pel, "PEL");
9811 write_met_bin_2d(out, met, met->cape, "CAPE");
9812 write_met_bin_2d(out, met, met->cin, "CIN");
9813
9814 /* Write level data... */
9815 write_met_bin_3d(out, ctl, met, met->z, "Z",
9816 (ctl->met_zfp_tol_z <= 0 ? ctl->met_zfp_prec : 0),
9817 ctl->met_zfp_tol_z);
9818 write_met_bin_3d(out, ctl, met, met->t, "T",
9819 (ctl->met_zfp_tol_t <= 0 ? ctl->met_zfp_prec : 0),
9820 ctl->met_zfp_tol_t);
9821 write_met_bin_3d(out, ctl, met, met->u, "U", ctl->met_zfp_prec, 0);
9822 write_met_bin_3d(out, ctl, met, met->v, "V", ctl->met_zfp_prec, 0);
9823 write_met_bin_3d(out, ctl, met, met->w, "W", ctl->met_zfp_prec, 0);
9824 write_met_bin_3d(out, ctl, met, met->pv, "PV", ctl->met_zfp_prec, 0);
9825 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", ctl->met_zfp_prec, 0);
9826 write_met_bin_3d(out, ctl, met, met->o3, "O3", ctl->met_zfp_prec, 0);
9827 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", ctl->met_zfp_prec, 0);
9828 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", ctl->met_zfp_prec, 0);
9829 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", ctl->met_zfp_prec, 0);
9830 write_met_bin_3d(out, ctl, met, met->swc, "SWC", ctl->met_zfp_prec, 0);
9831 write_met_bin_3d(out, ctl, met, met->cc, "CC", ctl->met_zfp_prec, 0);
9832
9833 /* Write final flag... */
9834 int final = 999;
9835 FWRITE(&final, int,
9836 1,
9837 out);
9838
9839 /* Close file... */
9840 fclose(out);
9841}
void write_met_bin_3d(FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int precision, const double tolerance)
Writes a 3-dimensional meteorological variable to a binary file.
Definition: mptrac.c:9874
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:9845
int met_zfp_prec
ZFP compression precision for all variables, except z and T.
Definition: mptrac.h:2497
double met_zfp_tol_t
ZFP compression tolerance for temperature.
Definition: mptrac.h:2500
double met_zfp_tol_z
ZFP compression tolerance for geopotential height.
Definition: mptrac.h:2503
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 9845 of file mptrac.c.

9849 {
9850
9851 float *help;
9852
9853 /* Allocate... */
9854 ALLOC(help, float,
9855 EX * EY);
9856
9857 /* Copy data... */
9858 for (int ix = 0; ix < met->nx; ix++)
9859 for (int iy = 0; iy < met->ny; iy++)
9860 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
9861
9862 /* Write uncompressed data... */
9863 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
9864 FWRITE(help, float,
9865 (size_t) (met->nx * met->ny),
9866 out);
9867
9868 /* Free... */
9869 free(help);
9870}

◆ write_met_bin_3d()

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

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

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

Parameters
outA pointer to a FILE structure representing the output file.
ctlA pointer to a ctl_t structure containing control parameters.
metA pointer to a met_t structure containing meteorological data.
varAn array of floats representing the 3-dimensional variable data.
varnameA string containing the name of the variable being written.
precisionAn integer specifying the precision of compression (for certain compression methods).
toleranceA double specifying the tolerance for compression (for certain compression methods).

The function performs the following steps:

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

Definition at line 9874 of file mptrac.c.

9881 {
9882
9883 float *help;
9884
9885 /* Allocate... */
9886 ALLOC(help, float,
9887 EX * EY * EP);
9888
9889 /* Copy data... */
9890#pragma omp parallel for default(shared) collapse(2)
9891 for (int ix = 0; ix < met->nx; ix++)
9892 for (int iy = 0; iy < met->ny; iy++)
9893 for (int ip = 0; ip < met->np; ip++)
9894 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
9895
9896 /* Write uncompressed data... */
9897 if (ctl->met_type == 1) {
9898 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
9899 FWRITE(help, float,
9900 (size_t) (met->nx * met->ny * met->np),
9901 out);
9902 }
9903
9904 /* Write packed data... */
9905 else if (ctl->met_type == 2)
9906 compress_pck(varname, help, (size_t) (met->ny * met->nx),
9907 (size_t) met->np, 0, out);
9908
9909 /* Write zfp data... */
9910#ifdef ZFP
9911 else if (ctl->met_type == 3) {
9912 FWRITE(&precision, int,
9913 1,
9914 out);
9915 FWRITE(&tolerance, double,
9916 1,
9917 out);
9918 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
9919 tolerance, 0, out);
9920 }
9921#endif
9922
9923 /* Write zstd data... */
9924#ifdef ZSTD
9925 else if (ctl->met_type == 4)
9926 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
9927 out);
9928#endif
9929
9930 /* Write cmultiscale data... */
9931#ifdef CMS
9932 else if (ctl->met_type == 5) {
9933 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
9934 (size_t) met->np, 0, out);
9935 }
9936#endif
9937
9938 /* Unknown method... */
9939 else {
9940 ERRMSG("MET_TYPE not supported!");
9941 LOG(3, "%d %g", precision, tolerance);
9942 }
9943
9944 /* Free... */
9945 free(help);
9946}
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 9950 of file mptrac.c.

9953 {
9954
9955 /* Create file... */
9956 int ncid, varid;
9957 size_t start[4], count[4];
9958 nc_create(filename, NC_NETCDF4, &ncid);
9959
9960 /* Define dimensions... */
9961 int tid, lonid, latid, levid;
9962 NC(nc_def_dim(ncid, "time", 1, &tid));
9963 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
9964 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
9965 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
9966
9967 /* Define grid... */
9968 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
9969 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
9970 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
9971 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
9972 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
9973
9974 /* Define surface variables... */
9975 int dimid2[2] = { latid, lonid };
9976 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
9977 ctl->met_nc_level, 0);
9978 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
9979 ctl->met_nc_level, 0);
9980 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
9981 ctl->met_nc_level, 0);
9982 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
9983 "m s**-1", ctl->met_nc_level, 0);
9984 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
9985 "m s**-1", ctl->met_nc_level, 0);
9986 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
9987 ctl->met_nc_level, 0);
9988 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
9989 ctl->met_nc_level, 0);
9990
9991 /* Define level data... */
9992 int dimid3[3] = { levid, latid, lonid };
9993 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
9994 ctl->met_nc_level, ctl->met_nc_quant);
9995 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
9996 ctl->met_nc_level, ctl->met_nc_quant);
9997 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
9998 ctl->met_nc_level, ctl->met_nc_quant);
9999 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
10000 ctl->met_nc_level, ctl->met_nc_quant);
10001 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
10002 ctl->met_nc_level, ctl->met_nc_quant);
10003 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
10004 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10005 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
10006 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10007 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
10008 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10009 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
10010 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10011 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
10012 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10013 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
10014 ctl->met_nc_level, ctl->met_nc_quant);
10015
10016 /* End definitions... */
10017 NC(nc_enddef(ncid));
10018
10019 /* Write grid data... */
10020 NC_PUT_DOUBLE("time", &met->time, 0);
10021 NC_PUT_DOUBLE("lon", met->lon, 0);
10022 NC_PUT_DOUBLE("lat", met->lat, 0);
10023 double phelp[EP];
10024 for (int ip = 0; ip < met->np; ip++)
10025 phelp[ip] = 100. * met->p[ip];
10026 NC_PUT_DOUBLE("lev", phelp, 0);
10027
10028 /* Write surface data... */
10029 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
10030 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
10031 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
10032 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
10033 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
10034 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
10035 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
10036
10037 /* Write level data... */
10038 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
10039 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
10040 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
10041 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
10042 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
10043 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
10044 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
10045 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
10046 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
10047 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
10048 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
10049
10050 /* Close file... */
10051 NC(nc_close(ncid));
10052}
void write_met_nc_2d(int ncid, const char *varname, met_t *met, float var[EX][EY], float scl)
Writes a 2D meteorological variable to a NetCDF file.
Definition: mptrac.c:10056
void write_met_nc_3d(int ncid, const char *varname, met_t *met, float var[EX][EY][EP], float scl)
Writes a 3D meteorological variable to a NetCDF file.
Definition: mptrac.c:10085
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2494
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2491
Here is the call graph for this function:

◆ write_met_nc_2d()

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

Writes a 2D meteorological variable to a NetCDF file.

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

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

Definition at line 10056 of file mptrac.c.

10061 {
10062
10063 int varid;
10064 size_t start[4], count[4];
10065
10066 /* Allocate... */
10067 float *help;
10068 ALLOC(help, float,
10069 EX * EY);
10070
10071 /* Copy data... */
10072 for (int ix = 0; ix < met->nx; ix++)
10073 for (int iy = 0; iy < met->ny; iy++)
10074 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
10075
10076 /* Write data... */
10077 NC_PUT_FLOAT(varname, help, 0);
10078
10079 /* Free... */
10080 free(help);
10081}
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1135

◆ write_met_nc_3d()

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

Writes a 3D meteorological variable to a NetCDF file.

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

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

Definition at line 10085 of file mptrac.c.

10090 {
10091
10092 int varid;
10093 size_t start[4], count[4];
10094
10095 /* Allocate... */
10096 float *help;
10097 ALLOC(help, float,
10098 EX * EY * EP);
10099
10100 /* Copy data... */
10101 for (int ix = 0; ix < met->nx; ix++)
10102 for (int iy = 0; iy < met->ny; iy++)
10103 for (int ip = 0; ip < met->np; ip++)
10104 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
10105
10106 /* Write data... */
10107 NC_PUT_FLOAT(varname, help, 0);
10108
10109 /* Free... */
10110 free(help);
10111}

◆ write_output()

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

10121 {
10122
10123 char ext[10], filename[2 * LEN];
10124
10125 double r;
10126
10127 int year, mon, day, hour, min, sec;
10128
10129 /* Get time... */
10130 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
10131
10132 /* Update host... */
10133#ifdef _OPENACC
10134 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
10135 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
10136 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
10137 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
10138 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
10139 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0)) {
10140 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_D2H);
10141#pragma acc update host(atm[:1])
10142 }
10143#endif
10144
10145 /* Write atmospheric data... */
10146 if (ctl->atm_basename[0] != '-' &&
10147 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
10148 if (ctl->atm_type_out == 0)
10149 sprintf(ext, "tab");
10150 else if (ctl->atm_type_out == 1)
10151 sprintf(ext, "bin");
10152 else if (ctl->atm_type_out == 2)
10153 sprintf(ext, "nc");
10154 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
10155 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
10156 write_atm(filename, ctl, atm, t);
10157 }
10158
10159 /* Write gridded data... */
10160 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
10161 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
10162 dirname, ctl->grid_basename, year, mon, day, hour, min,
10163 ctl->grid_type == 0 ? "tab" : "nc");
10164 write_grid(filename, ctl, met0, met1, atm, t);
10165 }
10166
10167 /* Write CSI data... */
10168 if (ctl->csi_basename[0] != '-') {
10169 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
10170 write_csi(filename, ctl, atm, t);
10171 }
10172
10173 /* Write ensemble data... */
10174 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
10175 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
10176 dirname, ctl->ens_basename, year, mon, day, hour, min);
10177 write_ens(filename, ctl, atm, t);
10178 }
10179
10180 /* Write profile data... */
10181 if (ctl->prof_basename[0] != '-') {
10182 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
10183 write_prof(filename, ctl, met0, met1, atm, t);
10184 }
10185
10186 /* Write sample data... */
10187 if (ctl->sample_basename[0] != '-') {
10188 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
10189 write_sample(filename, ctl, met0, met1, atm, t);
10190 }
10191
10192 /* Write station data... */
10193 if (ctl->stat_basename[0] != '-') {
10194 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
10195 write_station(filename, ctl, atm, t);
10196 }
10197
10198 /* Write VTK data... */
10199 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
10200 static int nvtk;
10201 if (t == ctl->t_start)
10202 nvtk = 0;
10203 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
10204 write_vtk(filename, ctl, atm, t);
10205 }
10206}
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:9186
void 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:8472
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:10210
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:10600
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:10686
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:10437
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:9283
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:8924
Here is the call graph for this function:

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

10216 {
10217
10218 static FILE *out;
10219
10220 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
10221 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
10222
10223 static int nobs, *obscount, ip, okay;
10224
10225 /* Set timer... */
10226 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
10227
10228 /* Init... */
10229 if (t == ctl->t_start) {
10230
10231 /* Check quantity index for mass... */
10232 if (ctl->qnt_m < 0)
10233 ERRMSG("Need quantity mass!");
10234
10235 /* Check molar mass... */
10236 if (ctl->molmass <= 0)
10237 ERRMSG("Specify molar mass!");
10238
10239 /* Allocate... */
10240 ALLOC(lon, double,
10241 ctl->prof_nx);
10242 ALLOC(lat, double,
10243 ctl->prof_ny);
10244 ALLOC(area, double,
10245 ctl->prof_ny);
10246 ALLOC(z, double,
10247 ctl->prof_nz);
10248 ALLOC(press, double,
10249 ctl->prof_nz);
10250 ALLOC(rt, double,
10251 NOBS);
10252 ALLOC(rz, double,
10253 NOBS);
10254 ALLOC(rlon, double,
10255 NOBS);
10256 ALLOC(rlat, double,
10257 NOBS);
10258 ALLOC(robs, double,
10259 NOBS);
10260
10261 /* Read observation data... */
10262 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
10263
10264 /* Create new output file... */
10265 LOG(1, "Write profile data: %s", filename);
10266 if (!(out = fopen(filename, "w")))
10267 ERRMSG("Cannot create file!");
10268
10269 /* Write header... */
10270 fprintf(out,
10271 "# $1 = time [s]\n"
10272 "# $2 = altitude [km]\n"
10273 "# $3 = longitude [deg]\n"
10274 "# $4 = latitude [deg]\n"
10275 "# $5 = pressure [hPa]\n"
10276 "# $6 = temperature [K]\n"
10277 "# $7 = volume mixing ratio [ppv]\n"
10278 "# $8 = H2O volume mixing ratio [ppv]\n"
10279 "# $9 = O3 volume mixing ratio [ppv]\n"
10280 "# $10 = observed BT index [K]\n"
10281 "# $11 = number of observations\n");
10282
10283 /* Set grid box size... */
10284 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
10285 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
10286 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
10287
10288 /* Set vertical coordinates... */
10289 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10290 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
10291 press[iz] = P(z[iz]);
10292 }
10293
10294 /* Set horizontal coordinates... */
10295 for (int ix = 0; ix < ctl->prof_nx; ix++)
10296 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
10297 for (int iy = 0; iy < ctl->prof_ny; iy++) {
10298 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
10299 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
10300 }
10301 }
10302
10303 /* Set time interval... */
10304 const double t0 = t - 0.5 * ctl->dt_mod;
10305 const double t1 = t + 0.5 * ctl->dt_mod;
10306
10307 /* Allocate... */
10308 ALLOC(mass, double,
10309 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
10310 ALLOC(obsmean, double,
10311 ctl->prof_nx * ctl->prof_ny);
10312 ALLOC(obscount, int,
10313 ctl->prof_nx * ctl->prof_ny);
10314
10315 /* Loop over observations... */
10316 for (int i = 0; i < nobs; i++) {
10317
10318 /* Check time... */
10319 if (rt[i] < t0)
10320 continue;
10321 else if (rt[i] >= t1)
10322 break;
10323
10324 /* Check observation data... */
10325 if (!isfinite(robs[i]))
10326 continue;
10327
10328 /* Calculate indices... */
10329 int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
10330 int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
10331
10332 /* Check indices... */
10333 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
10334 continue;
10335
10336 /* Get mean observation index... */
10337 int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
10338 obsmean[idx] += robs[i];
10339 obscount[idx]++;
10340 }
10341
10342 /* Analyze model data... */
10343 for (ip = 0; ip < atm->np; ip++) {
10344
10345 /* Check time... */
10346 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10347 continue;
10348
10349 /* Get indices... */
10350 int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
10351 int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
10352 int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
10353
10354 /* Check indices... */
10355 if (ix < 0 || ix >= ctl->prof_nx ||
10356 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
10357 continue;
10358
10359 /* Get total mass in grid cell... */
10360 int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10361 mass[idx] += atm->q[ctl->qnt_m][ip];
10362 }
10363
10364 /* Extract profiles... */
10365 for (int ix = 0; ix < ctl->prof_nx; ix++)
10366 for (int iy = 0; iy < ctl->prof_ny; iy++) {
10367 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
10368 if (obscount[idx2] > 0) {
10369
10370 /* Check profile... */
10371 okay = 0;
10372 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10373 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10374 if (mass[idx3] > 0) {
10375 okay = 1;
10376 break;
10377 }
10378 }
10379 if (!okay)
10380 continue;
10381
10382 /* Write output... */
10383 fprintf(out, "\n");
10384
10385 /* Loop over altitudes... */
10386 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10387
10388 /* Get temperature, water vapor, and ozone... */
10390 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
10391 lon[ix], lat[iy], &temp, ci, cw, 1);
10392 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
10393 lon[ix], lat[iy], &h2o, ci, cw, 0);
10394 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
10395 lon[ix], lat[iy], &o3, ci, cw, 0);
10396
10397 /* Calculate volume mixing ratio... */
10398 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10399 vmr = MA / ctl->molmass * mass[idx3]
10400 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
10401
10402 /* Write output... */
10403 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
10404 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
10405 obsmean[idx2] / obscount[idx2], obscount[idx2]);
10406 }
10407 }
10408 }
10409
10410 /* Free... */
10411 free(mass);
10412 free(obsmean);
10413 free(obscount);
10414
10415 /* Finalize... */
10416 if (t == ctl->t_stop) {
10417
10418 /* Close output file... */
10419 fclose(out);
10420
10421 /* Free... */
10422 free(lon);
10423 free(lat);
10424 free(area);
10425 free(z);
10426 free(press);
10427 free(rt);
10428 free(rz);
10429 free(rlon);
10430 free(rlat);
10431 free(robs);
10432 }
10433}
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 10437 of file mptrac.c.

10443 {
10444
10445 static FILE *out;
10446
10447 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
10448 kw[EP];
10449
10450 static int nobs, nk;
10451
10452 /* Set timer... */
10453 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
10454
10455 /* Init... */
10456 if (t == ctl->t_start) {
10457
10458 /* Allocate... */
10459 ALLOC(rt, double,
10460 NOBS);
10461 ALLOC(rz, double,
10462 NOBS);
10463 ALLOC(rlon, double,
10464 NOBS);
10465 ALLOC(rlat, double,
10466 NOBS);
10467 ALLOC(robs, double,
10468 NOBS);
10469
10470 /* Read observation data... */
10471 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
10472
10473 /* Read kernel data... */
10474 if (ctl->sample_kernel[0] != '-')
10475 read_kernel(ctl->sample_kernel, kz, kw, &nk);
10476
10477 /* Create output file... */
10478 LOG(1, "Write sample data: %s", filename);
10479 if (!(out = fopen(filename, "w")))
10480 ERRMSG("Cannot create file!");
10481
10482 /* Write header... */
10483 fprintf(out,
10484 "# $1 = time [s]\n"
10485 "# $2 = altitude [km]\n"
10486 "# $3 = longitude [deg]\n"
10487 "# $4 = latitude [deg]\n"
10488 "# $5 = surface area [km^2]\n"
10489 "# $6 = layer depth [km]\n"
10490 "# $7 = number of particles [1]\n"
10491 "# $8 = column density [kg/m^2]\n"
10492 "# $9 = volume mixing ratio [ppv]\n"
10493 "# $10 = observed BT index [K]\n\n");
10494
10495 /* Set latitude range, squared radius, and area... */
10496 dlat = DY2DEG(ctl->sample_dx);
10497 rmax2 = SQR(ctl->sample_dx);
10498 area = M_PI * rmax2;
10499 }
10500
10501 /* Set time interval for output... */
10502 const double t0 = t - 0.5 * ctl->dt_mod;
10503 const double t1 = t + 0.5 * ctl->dt_mod;
10504
10505 /* Loop over observations... */
10506 for (int i = 0; i < nobs; i++) {
10507
10508 /* Check time... */
10509 if (rt[i] < t0)
10510 continue;
10511 else if (rt[i] >= t1)
10512 break;
10513
10514 /* Calculate Cartesian coordinates... */
10515 double x0[3];
10516 geo2cart(0, rlon[i], rlat[i], x0);
10517
10518 /* Set pressure range... */
10519 const double rp = P(rz[i]);
10520 double ptop = P(rz[i] + ctl->sample_dz);
10521 double pbot = P(rz[i] - ctl->sample_dz);
10522
10523 /* Init... */
10524 double mass = 0;
10525 int np = 0;
10526
10527 /* Loop over air parcels... */
10528#pragma omp parallel for default(shared) reduction(+:mass,np)
10529 for (int ip = 0; ip < atm->np; ip++) {
10530
10531 /* Check time... */
10532 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10533 continue;
10534
10535 /* Check latitude... */
10536 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
10537 continue;
10538
10539 /* Check horizontal distance... */
10540 double x1[3];
10541 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
10542 if (DIST2(x0, x1) > rmax2)
10543 continue;
10544
10545 /* Check pressure... */
10546 if (ctl->sample_dz > 0)
10547 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
10548 continue;
10549
10550 /* Add mass... */
10551 if (ctl->qnt_m >= 0)
10552 mass +=
10553 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
10554 np++;
10555 }
10556
10557 /* Calculate column density... */
10558 const double cd = mass / (1e6 * area);
10559
10560 /* Calculate volume mixing ratio... */
10561 double vmr = 0;
10562 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
10563 if (mass > 0) {
10564
10565 /* Get temperature... */
10566 double temp;
10568 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
10569 rlon[i], rlat[i], &temp, ci, cw, 1);
10570
10571 /* Calculate volume mixing ratio... */
10572 vmr = MA / ctl->molmass * mass
10573 / (RHO(rp, temp) * 1e6 * area * 1e3 * ctl->sample_dz);
10574 }
10575 } else
10576 vmr = NAN;
10577
10578 /* Write output... */
10579 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
10580 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
10581 }
10582
10583 /* Finalize...... */
10584 if (t == ctl->t_stop) {
10585
10586 /* Close output file... */
10587 fclose(out);
10588
10589 /* Free... */
10590 free(rt);
10591 free(rz);
10592 free(rlon);
10593 free(rlat);
10594 free(robs);
10595 }
10596}
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 10600 of file mptrac.c.

10604 {
10605
10606 static FILE *out;
10607
10608 static double rmax2, x0[3], x1[3];
10609
10610 /* Set timer... */
10611 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
10612
10613 /* Init... */
10614 if (t == ctl->t_start) {
10615
10616 /* Write info... */
10617 LOG(1, "Write station data: %s", filename);
10618
10619 /* Create new file... */
10620 if (!(out = fopen(filename, "w")))
10621 ERRMSG("Cannot create file!");
10622
10623 /* Write header... */
10624 fprintf(out,
10625 "# $1 = time [s]\n"
10626 "# $2 = altitude [km]\n"
10627 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
10628 for (int iq = 0; iq < ctl->nq; iq++)
10629 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
10630 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10631 fprintf(out, "\n");
10632
10633 /* Set geolocation and search radius... */
10634 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
10635 rmax2 = SQR(ctl->stat_r);
10636 }
10637
10638 /* Set time interval for output... */
10639 const double t0 = t - 0.5 * ctl->dt_mod;
10640 const double t1 = t + 0.5 * ctl->dt_mod;
10641
10642 /* Loop over air parcels... */
10643 for (int ip = 0; ip < atm->np; ip++) {
10644
10645 /* Check time... */
10646 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10647 continue;
10648
10649 /* Check time range for station output... */
10650 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
10651 continue;
10652
10653 /* Check station flag... */
10654 if (ctl->qnt_stat >= 0)
10655 if ((int) atm->q[ctl->qnt_stat][ip])
10656 continue;
10657
10658 /* Get Cartesian coordinates... */
10659 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
10660
10661 /* Check horizontal distance... */
10662 if (DIST2(x0, x1) > rmax2)
10663 continue;
10664
10665 /* Set station flag... */
10666 if (ctl->qnt_stat >= 0)
10667 atm->q[ctl->qnt_stat][ip] = 1;
10668
10669 /* Write data... */
10670 fprintf(out, "%.2f %g %g %g",
10671 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
10672 for (int iq = 0; iq < ctl->nq; iq++) {
10673 fprintf(out, " ");
10674 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
10675 }
10676 fprintf(out, "\n");
10677 }
10678
10679 /* Close file... */
10680 if (t == ctl->t_stop)
10681 fclose(out);
10682}
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 10686 of file mptrac.c.

10690 {
10691
10692 FILE *out;
10693
10694 /* Set timer... */
10695 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
10696
10697 /* Write info... */
10698 LOG(1, "Write VTK data: %s", filename);
10699
10700 /* Set time interval for output... */
10701 const double t0 = t - 0.5 * ctl->dt_mod;
10702 const double t1 = t + 0.5 * ctl->dt_mod;
10703
10704 /* Create file... */
10705 if (!(out = fopen(filename, "w")))
10706 ERRMSG("Cannot create file!");
10707
10708 /* Count data points... */
10709 int np = 0;
10710 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10711 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10712 continue;
10713 np++;
10714 }
10715
10716 /* Write header... */
10717 fprintf(out,
10718 "# vtk DataFile Version 3.0\n"
10719 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
10720
10721 /* Write point coordinates... */
10722 fprintf(out, "POINTS %d float\n", np);
10723 if (ctl->vtk_sphere) {
10724 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10725 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10726 continue;
10727 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
10728 + ctl->vtk_offset) / RE;
10729 const double coslat = cos(DEG2RAD(atm->lat[ip]));
10730 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
10731 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
10732 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
10733 fprintf(out, "%g %g %g\n", x, y, z);
10734 }
10735 } else
10736 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10737 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10738 continue;
10739 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
10740 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
10741 }
10742
10743 /* Write point data... */
10744 fprintf(out, "POINT_DATA %d\n", np);
10745 for (int iq = 0; iq < ctl->nq; iq++) {
10746 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
10747 ctl->qnt_name[iq]);
10748 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10749 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10750 continue;
10751 fprintf(out, "%g\n", atm->q[iq][ip]);
10752 }
10753 }
10754
10755 /* Close file... */
10756 fclose(out);
10757}